美文网首页vue
wepack从0开始配置vue环境之一: 基础配置

wepack从0开始配置vue环境之一: 基础配置

作者: 胖太_91bf | 来源:发表于2018-04-05 08:00 被阅读136次

    github传送门 dev分支
    webpack之二webpack部署优化
    webpack之三集成vuex和vue-Router
    webpack之四集成ssr

    • 创建项目根目录

    • 在vscode中打开, 在终端中输入

    // cd到项目目录
    cnpm init -y
    

    生成package.json文件

    • 安装webpack和vue, vue-loader

    cnpm i webpack vue-loader webpack@3 -D
    cnpm i vue -S
    // 安装完成根据warning安装需要的依赖
    css-loader vue-template-compiler -D
    
    • 创建src/app.vue

    <template>
      <div class="text">{{text}}</div>
    </template>
    <script>
    export default {
      data () {
        return {
          text: 'abc'
        }
      }
    }
    </script>
    <style>
      .text {
        color: red;
      }
    </style>
    
    • 创建/webpack.config.js

     const path = require('path')
    
    module.exports = {
      entry: path.join(__dirname, 'src/index.js'),
      output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.vue$/, 
            loader: 'vue-loader'
          }
        ]
      }
    }
    
    • 创建/src/index.js 入口js文件

    import Vue from 'vue'
    import App from './app.vue'
    
    const root = document.createElement('div')
    document.body.appendChild(root)
    
    new Vue({
      render: h => h(App)
    }).$mount(root)
    
    • 安装style-loader和css-loader, url-loader, file-loader, 处理css和图片文件

    cnpm i style-loader url-loader file-loader -D
    url-loader依赖于file-loader
    module: {
        rules: [
          {
            test: /\.vue$/, 
            loader: 'vue-loader'
          },
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
          },
          {
            test: /\.(jpg|png|svg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192,
                  name: '[name]-kay.[ext]'
                }
              }
            ]
          }
        ]
      }
    
    • 安装rimraf 在build之前删除dist目录

    cnpm i rimraf -D
    //在package.json.script中添加cli
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "npm run clean && webpack --config webpack.config.js",
        "clean": "rimraf dist"
      },
    
    • 嵌入stylus: 安装stylus和stylus-loader

    cnpm i stylus stylus-loader -D
    {
        test: /\.styl$/,
          use: [
            'style-loader',
            'css-loader',
            'stylus-loader'
          ]
    },
    
    • 使用webpack-dev-server => 开发环境

    安装cross-env区分开发环境和生产环境
    配置html模板html-webpack-plugin
    配置webpack全局常量插件webpack.DefinePlugin()
    变更webpack.config.js结构
    在package.json.script里添加dev命令

    cnpm i webpac-dev-server@2 cross-env 
     -D
    cnpm i html-webpack-plugin -D
    //package.json.script
        "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
    
    // 代码
    const path = require('path')
    const webpack = require('webpack')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
      target: 'web',
      resolve: {
        alias: {
          '@assets':path.join(__dirname, 'src/assets')
        }
      },
      entry: path.join(__dirname, 'src/index.js'),
      output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.vue$/, 
            loader: 'vue-loader'
          },
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
          },
          {
            test: /\.styl$/,
            use: [
              'style-loader',
              'css-loader',
              'stylus-loader'
            ]
          },
          {
            test: /\.(jpg|png|svg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192,
                  name: '[name]-kay.[ext]'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: isDev ? '"development"' : '"production"'
          }
        }),
        new HtmlWebpackPlugin()
      ]
    }
    
    if (isDev) {
      config.devServer = {
        port: 8001,
        host: '0.0.0.0',
        overlay: {
          errors: true
        }
      }
    }
    
    module.exports = config
    // 终端输入 npm run dev启动项目
    
    • webpack-dev-server配合vue热更替功能实现

    使用webpack.HotModuleReplacementPlugin和webpack.NoEmitOnErrorsPlugin
    配置devServer.hot = true
    css热更替使用vue-style-loader代替style-loader

    if (isDev) {
      config.devServer = {
        port: 8001,
        host: '0.0.0.0',
        overlay: {
          errors: true
        },
        hot: true
      }
      config.plugins.push(
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
      )
    }
    
    • 配置source-map方便调试

    config.devtool = '#cheap-module-eval-source-map'
    
    • 配置jsx和postcss
      安装postcss-loader, autoprefixer babel-loader, babel-core,babel-preset-env, babel-plugin-transform-vue-jsx,babel-plugin-syntax-jsx, (babel-helper-vue-jsx-merge-props)
      统一cnpm安装下
      创建/.babelrc, /postcss.config.js并分别配置
    // .babelrc
    {
      "presets":[
        "env"
      ],
      "plugins": [
        "transform-vue-jsx"
      ]
    }
    // postcss.config.js
    const autoprefixer = require('autoprefixer')
    module.exports = {
      plugins: [
        autoprefixer()
      ]
    }
    // 在devServer里添加babel-loader和postcss-loader
    {
            test: /\.js$/,
            loader: 'babel-loader'
          },
          {
            test: /\.jsx$/,
            loader: 'babel-loader'
          },
    {
            test: /\.styl$/,
            use: [
              'style-loader',
              'css-loader',
              {
                loader: 'postcss-loader',
                options: {
                  sourceMap: true
                }
              },
              'stylus-loader'
            ]
          },
    
    • 测试jsx-vue模板

    新建/src/views/test.jsx

    export default {
      data () {
        return {
          test: '这是用jsx语法写的vue模板'
        }
      },
      render () {
        return (
          <div>
            {this.test}
          </div>
        )
      }
    }
    
    • css文件分离打包成单独文件

    使用extract-text-webpack-plugin
    分离打包需要区分环境,删除config目录上的stylus-loader, 并在对应环境下对应loader配置
    /webpack.config.js重写后配置如下

    const path = require('path')
    const webpack = require('webpack')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const ExtartTextPlugin = require('extract-text-webpack-plugin')
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
      target: 'web',
      resolve: {
        alias: {
          '@assets':path.join(__dirname, 'src/assets')
        }
      },
      entry: path.join(__dirname, 'src/index.js'),
      output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.vue$/, 
            loader: 'vue-loader'
          },
          {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
          },
          {
            test: /\.jsx$/,
            loader: 'babel-loader'
          },
          {
            test: /\.(jpg|png|svg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192,
                  name: '[name]-kay.[ext]'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: isDev ? '"development"' : '"production"'
          }
        }),
        new HtmlWebpackPlugin()
      ]
    }
    
    if (isDev) {
      config.module.rules.push({
        test: /\.styl$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          'stylus-loader'
        ]
      })
      config.devtool = '#cheap-module-eval-source-map'
      config.devServer = {
        port: 8001,
        host: '0.0.0.0',
        overlay: {
          errors: true
        },
        hot: true
      }
      config.plugins.push(
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
      )
    } else {
      config.module.rules.push({
        test: /\.styl$/,
        use: ExtartTextPlugin.extract({
          fallback: "style-loader",
          use: [
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true
              }
            },
            'stylus-loader'
          ]
        })
      })
      config.plugins.push(
        new ExtartTextPlugin({
          filename: 'style.[contenthash:8].css'
        })
      )
    }
    
    module.exports = config
    
    • 单独打包类库文件, 实现缓存优化性能

    修改线上环境entry选项使用options模式为js文件添加name属性app和vendor -> 是output中[name]的由来,将开发环境的output.filename修改为'bundle.[hash:8].js',
    正式环境修改为: '[name].[chunkhash:8].js'(不可以使用hash, webpack-dev-server会报错)
    hash和chunkhash的区别:使用hash会让app和vendor的hash码一样是整个应用的hash(如果某个js文件改变了, 说有js文件的hash也会跟着改变, 正式环境就 没有意义了), 而chunkhash是每一个模块或者说节点单独生成hash,
    使用
    webpack.optimize.CommonsChunkPlugin({name: 'vendor'})
    单独打包webpack相关的js代码:(好处是在有新的模块加入时候, webpack会给模块加id, 如果在中间插入会改变之前代码的id, 这样会导致hash变化破坏缓存, 需要单独打包)vendor必须在runtime之前
    使用webpack.optimizeCommonsChunkPlugin({name: 'runtime'})
    /webpack.config.js修改为:

    const path = require('path')
    const webpack = require('webpack')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const ExtartTextPlugin = require('extract-text-webpack-plugin')
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
      target: 'web',
      resolve: {
        alias: {
          '@assets':path.join(__dirname, 'src/assets')
        }
      },
      entry: path.join(__dirname, 'src/index.js'),
      output: {
        filename: 'bundle.[hash:8].js',
        path: path.join(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.vue$/, 
            loader: 'vue-loader'
          },
          {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
          },
          {
            test: /\.jsx$/,
            loader: 'babel-loader'
          },
          {
            test: /\.(jpg|png|svg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192,
                  name: '[name]-kay.[ext]'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: isDev ? '"development"' : '"production"'
          }
        }),
        new HtmlWebpackPlugin()
      ]
    }
    
    if (isDev) {
      config.module.rules.push({
        test: /\.styl$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          'stylus-loader'
        ]
      })
      config.devtool = '#cheap-module-eval-source-map'
      config.devServer = {
        port: 8001,
        host: '0.0.0.0',
        overlay: {
          errors: true
        },
        hot: true
      }
      config.plugins.push(
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
      )
    } else {
      config.entry = {
        app: path.join(__dirname, 'src/index.js'),
        vendor: ['vue']
      }
      config.output.filename = '[name].[chunkhash:8].js'
      config.module.rules.push({
        test: /\.styl$/,
        use: ExtartTextPlugin.extract({
          fallback: "style-loader",
          use: [
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true
              }
            },
            'stylus-loader'
          ]
        })
      })
      config.plugins.push(
        new ExtartTextPlugin({
          filename: 'style.[contenthash:8].css'
        }),
        new webpack.optimize.CommonsChunkPlugin({
          name: 'vendor'
        }),
        new webpack.optimize.CommonsChunkPlugin({
          name: 'runtime'
        })
      )
    }
    
    module.exports = config
    
    • 生成环境压缩js

    使用webpack.optimize.UglifyJsPlugin()并配置options.compress.warnings = false, options.output.comments: false

    if(isDev) {
      ...
    } else {
      ...
    config.plugins.push(
        new ExtartTextPlugin({
          filename: 'style.[contenthash:8].css'
        }),
        new webpack.optimize.CommonsChunkPlugin({
          name: 'vendor'
        }),
        new webpack.optimize.CommonsChunkPlugin({
          name: 'runtime'
        }),
        new webpack.optimize.UglifyJsPlugin({
          compress: {
            warnings: false
          },
          output: {
            comments: false
          }
        })
      )
    }
    
    • 生成环境压缩css

    1. 安装optimize-css-assets-webpack-plugin@3
    2. 配置生成环境插件
    new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css$/,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: { discardComments: { removeAll: true } },
            canPrint: true
          })
    

    这一份简单webpack配置, 可以让vue跑起来, 但是远远不够, 接下来还会更新, 能够部署上线的配置和ssr服务器端渲染的配置
    wepack从0开始配置vue环境之二: 线上部署配置优化
    github地址可以下载源码来研究

    相关文章

      网友评论

        本文标题:wepack从0开始配置vue环境之一: 基础配置

        本文链接:https://www.haomeiwen.com/subject/jvjxhftx.html