vue-ci项目 webpack3.x升webpack4.x

老板要求将之前的vue项目升级一下版本,也就是webpack4.x版本,对于从来没有升级过项目的本人来说是个不小的挑战。
在此之前已经研究了一天的webpack4.x文档,说实话文档真的不容易吃透,还要慢慢摸索。

0配置
相比于webpack3,webpack4可以零配置运行,即webpack4的0配置也只是支持了默认entry 和 output而已,即默认entry为./src,默认output为/dist。

模式mode
就是相比于webpack3,webpack4新增了一个mode配置选择,用来表示配置模式的选择情况,也就是生产环境production、开发环境devolopment和自定义none这三个选择可选

optimization
webpack4.x已经移除了commonchunk插件,改用了optimization属性,运用起来就很灵活了。具体列子可以去官方文档上面看~

开始升级
1.首先node版本要>=8.9.4,我的版本目前是8.10.0,主要还是es6语法增多,得到新的原声支持。
2.webpack4.x版本需要安装webpack-cli
3.升级主要部件 webpack、webpack-bundle-analyzer、webpack-dev-server、webpack-merge
cnpm install -D webpack webpack-cli webpack-bundle-analyzer webpack-dev-server webpack-merge 如果这样安装在package里面版本没及时更新,那就先卸载之前的在重新安装
3.升级插件copy-webpack-plugin、css-loader、eslint-loader、file-loader、html-webpack-plugin、url-loader、friendly-errors-webpack-plugin、optimize-css-assets-webpack-plugin、uglifyjs-webpack-plugin
4.升级vue-loader,这个非常重要。cnpm uninstall -D vue-loader 我现在是14.4.2版本
5.卸载插件extract-text-webpack-plugin,webpack4.x已经不需要这个了,所以配置中的这个都可以删除了,然后安装mini-css-extract-plugin插件代替,具体用法什么的可以去官方文档上面去看。
6.如果有的小伙伴用到happypack插件进行多线程打包,一定要升级happypac!!!!!!!(重点,不然会报 'length’的错误)

配置
webpack.base.config.js
增加node:process.env.NODE_ENV 即
module.exports = {
mode: process.env.NODE_ENV,
},
去掉const ExtractTextPlugin = require(‘extract-text-webpack-plugin’)
安装const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
对应的

{
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader?minimize', 'autoprefixer-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.less$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader?minimize', 'autoprefixer-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },

修改成

{
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {loader: 'css-loader'}
        ]
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          {loader: 'css-loader'},
          {loader: 'less-loader'}
        ]
      },

然后这是我整个文件:

const path = require('path')
const os = require('os')
const webpack = require('webpack')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HappyPack = require('happypack')
require('babel-polyfill')
var happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
function resolve (dir) {
  return path.join(__dirname, dir)
}


module.exports = {
  mode: process.env.NODE_ENV,
  entry: {
    main: ['babel-polyfill', '@/main'],
    'vender-base': '@/vendors/vendors.base.js',
    'vender-exten': '@/vendors/vendors.exten.js'
  },
  output: {
    path: path.resolve(__dirname, '../dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            css: 'vue-style-loader!css-loader',
            less: 'vue-style-loader!css-loader!less-loader'
          },
          postLoaders: {
            html: 'babel-loader'
          }
        }
      },
      {
        test: /iview\/.*?js$/,
        loader: 'happypack/loader?id=happybabel',
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        loader: 'happypack/loader?id=happybabel',
        exclude: /node_modules/
      },
      {
        test: /\.js[x]?$/,
        include: [resolve('src')],
        exclude: /node_modules/,
        loader: 'happypack/loader?id=happybabel'
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {loader: 'css-loader'}
        ]
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          {loader: 'css-loader'},
          {loader: 'less-loader'}
        ]
      },
      {
        test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
        loader: 'url-loader?limit=1024'
      },
      {
        test: /\.(html|tpl)$/,
        loader: 'html-loader'
      }
    ]
  },
  plugins: [
    new HappyPack({
      id: 'happybabel',
      loaders: ['babel-loader'],
      threadPool: happyThreadPool,
      verbose: true
    }),
    new CopyWebpackPlugin([
      {
        from: 'node_modules/layui-src/dist/images/face',
        to: 'images/face'
      },
      {
        from: 'src/images/edi',
      },
    ])
  ],
  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      'vue': 'vue/dist/vue.esm.js',
      '@': resolve('../src'),
      'nodemodules': resolve('../node_modules'),
      'api': resolve('../src/api'),
      'libs': resolve('../src/libs'),
      'my-components': resolve('../src/views/my-components'),
      'system': resolve('../src/views/system'),
      'views': resolve('../src/views'),
      'jquery': 'layui-src/dist/lay/modules/jquery.js',
      'jQuery': 'layui-src/dist/lay/modules/jquery.js',
      'layui': 'layui-src/dist',
      'layui-lay': 'layui-src/dist/lay/modules'
    }
  }
}

webpack.dev.config.js
去掉const ExtractTextPlugin = require(‘extract-text-webpack-plugin’);
添加const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)

然后对应的

new ExtractTextPlugin({
            filename: '[name].css',
            allChunks: true
}),

修改成

new MiniCssExtractPlugin({
      filename: '[name].css',
      allChunks: true
}),

去掉

new webpack.optimize.CommonsChunkPlugin({
            name: ['vender-exten', 'vender-base'],
            minChunks: Infinity
 }),

这个详情说一下CommonsChunkPlugin已经废除,然后4.x中用optimize.SplitChunksPlugin代替,因为这里是测试环境,所以不需要对这个做太多处理,只针对生产环境,下面会说到,我当时在这里卡了好久了,dev出来,项目无任何报错,但是页面为空白,最后还是被我找到解决办法了哈哈哈。

整个文件代码:

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const merge = require('webpack-merge')
const webpackBaseConfig = require('./webpack.base.config.js')
const fs = require('fs')
const path = require('path')
const package = require('../package.json')
const config = require('./config.js')

fs.open('./build/env.js', 'w', function (err, fd) {
  const buf = 'export default "development";'
  fs.write(fd, buf, 0, buf.length, 0, function (err, written, buffer) {})
})

module.exports = merge(webpackBaseConfig, {
  mode: 'development',
  devtool: 'eval-source-map', // 指定加source-map的方式
  output: {
    publicPath: '/dist/',
    filename: '[name].js',
    chunkFilename: '[name].chunk.js'
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      allChunks: true
    }),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"development"'
      },
      webpackVar: {
        // 获取到cross-env定义的变量cusSystem
        cusSystem: JSON.stringify(process.env.cusSystem) || '""',
        cusRouter: JSON.stringify(process.env.cusRouter) || '""',
      }
    }),
    new HtmlWebpackPlugin({
      title: '汕头外代电商平台 v' + package.version,
      filename: '../index.html',
      inject: false,
      chunksSortMode: 'none' // 防止依赖包循环
    }),
    new CopyWebpackPlugin([
      {
        from: 'src/views/main-components/theme-switch/theme'
      },
      {
        from: 'src/views/my-components/text-editor/tinymce'
      }
    ], {
      ignore: [
        'text-editor.vue'
      ]
    }),
    new webpack.HotModuleReplacementPlugin(), //HMR
    new webpack.NamedModulesPlugin() // HMR
  ],
  // 设置跨域代理
  devServer: process.env.cusSystem ? config.devServer[process.env.cusSystem] : {
    historyApiFallback: true,
    hot: true,
    inline: true,
    stats: {colors: true},
    host: 'penavicost.gnway.cc',
    // host: '192.168.1.241',
    // port: 8066,
    disableHostCheck: true,
    proxy: {
      // 匹配代理的url
      '/api': {
        // 目标服务器地址
        target: 'http://pen.gnway.cc:8092',
        // target: 'http://hg.gnway.cc:8092',
        // target: 'http://qg.gnway.cc:8082',
        // target: 'http://lyb.gnway.cc:8092',

        // target: 'http://penavicost.l.gnway.cc', // 192.168.1.13服务器,记得要配置这个host
        // 路径重写
        pathRewrite: {'^/api': '/penavicost'}, // 连接192.168.1.13服务器可以不用重写接口路径
        changeOrigin: true
      }
    }
  }
})

webpack.prod.config.js
同理 ExtractTextPlugin去除,添加MiniCssExtractPlugin
去除

new webpack.optimize.CommonsChunkPlugin({
            // name: 'vendors',
            // filename: 'vendors.[hash].js'
            name: ['vender-exten', 'vender-base'],
            minChunks: Infinity
}),

写成这样

new webpack.optimize.SplitChunksPlugin({
      cacheGroups: {
        default: {
          minChunks: 2, // 最小 chunk ,默认1
          priority: -20, // 缓存组优先级
          reuseExistingChunk: true, // 可设置是否重用该chunk(查看源码没有发现默认值)
        },
        //打包重复出现的代码
        vendor: {
          chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
          minChunks: 2,
          maxInitialRequests: 5, // The default limit is too small to showcase the effect
          minSize: 0, // This is example is too small to create commons chunks
          name: 'vendor'
        },
        //打包第三方类库
        commons: {
          name: 'commons',
          chunks: 'initial',
          minChunks: Infinity
        }
      }
    }),
    new webpack.optimize.RuntimeChunkPlugin({
      name: 'manifest'
    }),

具体的属性值,用法看官方文档,这里不说明了~

然后是整个文件:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const UglifyJsParallelPlugin = require('webpack-uglify-parallel');
const merge = require('webpack-merge');
const webpackBaseConfig = require('./webpack.base.config.js');
const os = require('os');
const fs = require('fs');
const path = require('path');
const package = require('../package.json');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

fs.open('./build/env.js', 'w', function(err, fd) {
    const buf = 'export default "production";';
    fs.write(fd, buf, 0, buf.length, 0, function(err, written, buffer) {});
});

module.exports = merge(webpackBaseConfig, {
    output: {
        // publicPath: 'http://www.huoyunji.com/dist/',
        // publicPath: 'http://web.t.gnway.cc:8080/dist/', // 测试服务器
        publicPath: '',
        filename: '[name].[hash].js',
        chunkFilename: '[name].[hash].chunk.js'
    },
    plugins: [
        new cleanWebpackPlugin(['dist/*'], {
            root: path.resolve(__dirname, '../')
        }),
        new ExtractTextPlugin({
            filename: '[name].[hash].css',
            allChunks: true
        }),
        new webpack.optimize.CommonsChunkPlugin({
            // name: 'vendors',
            // filename: 'vendors.[hash].js'
            name: ['vender-exten', 'vender-base'],
            minChunks: Infinity
        }),
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"' // 项目中有使用该变量,不要轻易修改
            },
            webpackVar: {
                // 获取到cross-env定义的变量cusSystem
                // 生产环境的命令行暂时没定义变量cusSystem,因此都返回'""'
                cusSystem: JSON.stringify(process.env.cusSystem) || '""',
                cusRouter: JSON.stringify(process.env.cusRouter) || '""',
            }
        }),
        // new webpack.optimize.UglifyJsPlugin({
        //     compress: {
        //         warnings: false
        //     }
        // }),
        // new UglifyJSPlugin({ sourceMap: true }),
        new UglifyJSPlugin({
            parallel: true, // 并行压缩
            uglifyOptions: {
                compress: {
                    warnings: false,
                    drop_debugger: true, // true-去掉debugger的代码,默认就是true
                    // drop_console: true, // true-去掉console.*之类的代码,console.log与console.error等都会被清除掉;
                    pure_funcs: ['console.log'], // 可以删除对应的函数,这里暂时只删除console.log,留着console.error
                },
                // mangle: {
                //     safari10: true
                // }
            }
        }),
        // new UglifyJsParallelPlugin({
        //     workers: os.cpus().length,
        //     mangle: true,
        //     compressor: {
        //       warnings: false,
        //       drop_console: true,
        //       drop_debugger: true
        //      }
        // }),
        new CopyWebpackPlugin([
            {
                from: 'favicon.ico'
            },
            {
                from: 'src/styles/fonts',
                to: 'fonts'
            },
            {
                from: 'src/views/main-components/theme-switch/theme'
            },
            {
                from: 'src/views/my-components/text-editor/tinymce'
            }
        ], {
            ignore: [
                'text-editor.vue'
            ]
        }),
        new HtmlWebpackPlugin({
            title: '汕头外代电商平台 v' + package.version,
            favicon: './favicon.ico',
            filename: 'index.html',
            template: '!!ejs-loader!./src/template/index.ejs',
            inject: false
        })
    ]
});

最后附上package.json代码

{
  "name": "penavicost-frontend",
  "version": "1.0.0",
  "description": "汕头外代电商平台",
  "main": "index.js",
  "scripts": {
    "init": "webpack --progress --config build/webpack.dev.config.js",
    "dev": "webpack-dev-server --content-base ./ --open --inline --hot --compress --config build/webpack.dev.config.js",
    "dev2": "cross-env cusRouter=1 webpack-dev-server --content-base ./ --open --inline --hot --compress --config build/webpack.dev.config.js",
    "build": "webpack --progress --hide-modules --config build/webpack.prod.config.js",
    "lint": "eslint --fix --ext .js,.vue src",
    "test": "npm run lint"
  },
  "repository": {
    "type": "git",
    "url": "http://192.168.1.11:83/scm/git/penavicost-frontend"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@handsontable/vue": "^3.1.0",
    "area-data": "^1.0.0",
    "async-validator": "^1.8.2",
    "axios": "^0.17.1",
    "echarts": "^4.1.0",
    "fingerprintjs2": "^1.8.6",
    "handsontable": "^0.38.1",
    "iview": "^3.2.2",
    "iview-area": "^1.5.17",
    "js-cookie": "^2.2.0",
    "js-md5": "^0.7.3",
    "layui-src": "^2.3.0",
    "store": "^2.0.12",
    "tinymce": "^4.7.13",
    "vue": "^2.6.8",
    "vue-handsontable-official": "1.1.0",
    "vue-layer": "^0.9.10",
    "vue-router": "^3.0.1",
    "vuedraggable": "^2.16.0",
    "vuex": "^3.0.1",
    "vx-easyui": "^1.1.5"
  },
  "devDependencies": {
    "autoprefixer-loader": "^3.2.0",
    "babel": "^6.23.0",
    "babel-core": "^6.26.3",
    "babel-eslint": "^8.2.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-plugin-transform-runtime": "^6.12.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-3": "^6.24.1",
    "babel-runtime": "^6.26.0",
    "clean-webpack-plugin": "^0.1.19",
    "copy-webpack-plugin": "^5.0.2",
    "cross-env": "^5.2.0",
    "css-hot-loader": "^1.3.9",
    "css-loader": "^2.1.1",
    "ejs-loader": "^0.3.1",
    "eslint": "^4.19.1",
    "eslint-config-google": "^0.9.1",
    "eslint-config-standard": "^10.2.1",
    "eslint-loader": "^2.1.2",
    "eslint-plugin-html": "^4.0.3",
    "eslint-plugin-import": "^2.12.0",
    "eslint-plugin-node": "^5.2.1",
    "eslint-plugin-promise": "^3.8.0",
    "eslint-plugin-standard": "^3.1.0",
    "file-loader": "^3.0.1",
    "friendly-errors-webpack-plugin": "^1.7.0",
    "happypack": "^5.0.0-beta.4",
    "html-loader": "^0.5.4",
    "html-webpack-plugin": "^3.0.7",
    "less": "^2.7.3",
    "less-loader": "^4.1.0",
    "mini-css-extract-plugin": "^0.5.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "semver": "^5.4.1",
    "style-loader": "^0.19.1",
    "uglifyjs-webpack-plugin": "^2.1.2",
    "unsupported": "^1.1.0",
    "url-loader": "^1.1.2",
    "vue-hot-reload-api": "^2.3.0",
    "vue-html-loader": "^1.2.3",
    "vue-loader": "^14.2.4",
    "vue-style-loader": "^3.1.2",
    "vue-template-compiler": "^2.6.8",
    "webpack": "^4.29.6",
    "webpack-bundle-analyzer": "^3.1.0",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.2.1",
    "webpack-merge": "^4.2.1",
    "webpack-uglify-parallel": "^0.1.4"
  }
}

升级完后打包速度明显提升,而且包的体积明显也变小了
该文档只是一个参考,因为只有你升级的时候你才了解到更多其它知识点
结束

之后提交git,其它同事遇到import报错,解决方法加入"babel-plugin-dynamic-import-webpack": “^1.1.0” 插件,这样就不用删除依赖包,直接下载覆盖就可以了

你可能感兴趣的:(工作小记)