为了账号安全,请及时绑定邮箱和手机立即绑定

小记webpack4.x升级过程

项目背景

一期项目:《手把手从零打造企业级电商平台-前端实战

二期项目:《React16+React-Router4 从零打造企业级电商后台管理系统

第一个电商用户端课程在制作过程中用的是webpack@1.15.0,距离现在时间不算长,但这一年多时间webpack已经升级到v4了。1.15.0版本的最大好处就是能兼容IE8,所以对IE兼容性有要求的同学看到这就可以洗洗睡了。如果要升的话,这次升级的版本跨度应该是够大的。

第二个项目是React实现的电商后台管理系统,这个课程出来的时间要近一点,用到的技术也都是比较新的,webpack版本是3.x,跨度不是很大,所以这次并不准备对它升级。3到4的跨度不是很大,有兴趣的同学看完这个介绍,升级一下应该问题不大。

webpack@4.x的变化

先来说下webpack4和之前版本里一些主要的变化:

1、webpack不再支持node v4,这是因为新的webpack和附属插件使用了es6的语法,v4版本对es6不是很到位,所以,就不伺候了。

2、开始采取约定优于配置的思路,webpack@4.x里把很多选项都设置了默认值,比如入口就是./src,输出目录就是./dist,当然如果你自己去设置,它也不会拦着。所以在用webpack@4.x的时候,我们甚至都可以没有webpack.config.js这个配置文件也能一样打包。

3、拆分了旧版本里的webpack,分成了用来处理逻辑的webpack和提供可执行命令的webpack-cli,这也是有的同学把webpack装成新版本以后会报找不到webpack-cli模块这个错误的原因。

4、添加了mode选项,用来区分编译的环境,提供了development、production和none三个选项,理论上这个选项是强制指定的,其实不指定的话它也是有默认值的,但会给出一个warning,官方这么强烈建议了,就显式的指定一下吧。指定方式有两种,一是在启动命令里:

./node_modules/.bin/webpack --mode production

另外一种就是在配置文件里指定,方式如下:

var config = {
    mode: 'production'  // 可选development、production和none
}

5、配置上的变动,类似删除了commonChunksPlugin,用optimization来代替这种。还有loader的用法也和1.15.0不一样了,但这个升级是在之前版本里就有的,不是webpack@4.x带来的。

6、性能优化,提高了打包性能。另外从webpack2起,引入了Tree-shaking机制来提出没有被引用的模块。它的原理是按着引用关系重新建立一个新的依赖树,而没有被引用的模块就不会被打包到最后的代码里。之前的压缩优化方式是先把所有模块都挂到树上,然后通过分析后,删掉没被引用的模块。从字面意思来看,我觉得原来的方式更像在摇树,把没用的摇下来。这两种方式最后压缩完的结果可能类似,但设计思路完全是从两个方向走的。

7、其他。以上这些就是一些比较主要的变化,更详细的升级文档可以参考下官方的说明:https://github.com/webpack/webpack/releases

升级过程

1、升级nodejs,因为webpack4不再支持node v4以下的版本了,这里推荐6.12.3,升级完成后记得把项目里的node_modules删掉再重新install一遍。

2、按着以下版本重新安装依赖

  "devDependencies": {
    "css-loader": "^0.28.11",
    "file-loader": "^1.1.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.1.0",
    "style-loader": "^0.20.3",
    "url-loader": "^1.0.1",
    "webpack": "^4.2.0",
    "webpack-cli": "^2.0.13",
    "webpack-dev-server": "^3.1.1"
  },
  "dependencies": {
    "font-awesome": "^4.7.0",
    "hogan.js": "^3.0.2"
  }

安装插件的时候可以直接把package.json里的这些版本文件覆盖到原来项目里,然后删了node_modules目录,重新执行npm install。

当升级webpack时,其他插件的版本也要跟着升,这里面有两个插件要特别注意:

(1)webpack4里把原来版本里的webpack拆分成了两个东西,一个是webpack用来处理打包逻辑的,另外一个是webpack-cli是用来提供可执行命令的,webpack@4.x里这两个都要装。

(2)extract-text-webpack-plugin这个插件只有最新的beta版本能支持webpack@4.x,所以用命令安装的时候,需要指定版本,npm install extract-text-webpack-plugin@next --save-dev这样安装。

3、修改启动命令,把package.json里的scripts字段改成如下:

  "scripts": {
    "dev": "./node_modules/.bin/webpack-dev-server",
    "dev_win": "./node_modules/.bin/webpack-dev-server",
    "dist": "WEBPACK_ENV=online ./node_modules/.bin/webpack -p",
    "dist_win": "set WEBPACK_ENV=online&& ./node_modules/.bin/webpack -p"
  },

4、最后一步,修改webpack配置文件。下面把最新的配置文件粘出来,由webpack@1.15.0到webpack@4.x的变化都放在了配置文件的注释里:

/*
* @Author: Rosen
* @Date:   2017-05-08 15:28:19
* @Last Modified by:   Rosen
* @Last Modified time: 2018-03-27 13:10:36
*/
var webpack             = require('webpack');
var ExtractTextPlugin   = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin   = require('html-webpack-plugin');

// 环境变量配置,dev / online
var WEBPACK_ENV         = process.env.WEBPACK_ENV || 'dev';

// 获取html-webpack-plugin参数的方法 
var getHtmlConfig = function(name, title){
    return {
        template    : './src/view/' + name + '.html',
        filename    : 'view/' + name + '.html',
        favicon     : './favicon.ico',
        title       : title,
        inject      : true,
        hash        : true,
        chunks      : ['common', name]
    };
};
// webpack config
var config = {
    /* 
    * 【新增】:新增mode参数,webpack4中要指定模式,可以放在配置文件这里,也可以放在启动命令里,如--mode production
    */
    mode : 'dev' === WEBPACK_ENV ? 'development' : 'production',
    /* 
    * 【改动】:删除了入口文件的中括号,可选的改动,没什么影响
    */
    entry: {
        'common'            : './src/page/common/index.js',
        'index'             : './src/page/index/index.js',
        'list'              : './src/page/list/index.js',
        'detail'            : './src/page/detail/index.js',
        'cart'              : './src/page/cart/index.js',
        'order-confirm'     : './src/page/order-confirm/index.js',
        'order-list'        : './src/page/order-list/index.js',
        'order-detail'      : './src/page/order-detail/index.js',
        'payment'           : './src/page/payment/index.js',
        'user-login'        : './src/page/user-login/index.js',
        'user-register'     : './src/page/user-register/index.js',
        'user-pass-reset'   : './src/page/user-pass-reset/index.js',
        'user-center'       : './src/page/user-center/index.js',
        'user-center-update': './src/page/user-center-update/index.js',
        'user-pass-update'  : './src/page/user-pass-update/index.js',
        'result'            : './src/page/result/index.js',
        'about'             : './src/page/about/index.js',
    },
    output: {
        /* 
        * 【改动】:删除path的配置,在webpack4中文件默认生成的位置就是/dist,
        *  而publicPath和filename特性的设置要保留
        */
        // path        : __dirname + '/dist/',
        publicPath  : 'dev' === WEBPACK_ENV ? '/dist/' : '//s.happymmall.com/mmall-fe/dist/',
        filename    : 'js/[name].js'
    },
    externals : {
        'jquery' : 'window.jQuery'
    },
    module: {
        /* 
        * 【改动】:loader的使用中,loaders字段变为rules,用来放各种文件的加载器,用rules确实更为贴切
        */
        rules: [
            /* 
            * 【改动】:css样式的加载方式变化
            */
            // css文件的处理
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: "css-loader"
                })
            },
            /* 
            * 【改动】:模板文件的加载方式变化
            */
            // 模板文件的处理
            {
                test: /\.string$/,
                use: {
                    loader: 'html-loader',
                    options: {
                        minimize : true,
                        removeAttributeQuotes : false
                    }
                }
            },
            /* 
            * 【改动】:图片文件的加载方式变化,并和字体文件分开处理
            */
            // 图片的配置
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            /* 
                            * 【改动】:图片小于2kb的按base64打包
                            */
                            limit: 2048,
                            name: 'resource/[name].[ext]'
                        }
                    }
                ]
            },
            /* 
            * 【改动】:字体文件的加载方式变化
            */
            // 字体图标的配置
            {
                test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            name: 'resource/[name].[ext]'
                        }
                    }
                ]
            }
        ]
    },
    resolve : {
        alias : {
            node_modules    : __dirname + '/node_modules',
            util            : __dirname + '/src/util',
            page            : __dirname + '/src/page',
            service         : __dirname + '/src/service',
            image           : __dirname + '/src/image'
        }
    },
    /* 
    * 【新增】:webpack4里面移除了commonChunksPulgin插件,放在了config.optimization里面
    */
    optimization:{
        runtimeChunk: false,
        splitChunks: {
            cacheGroups: {
                common: {
                    name: "common",
                    chunks: "all",
                    minChunks: 2
                }
            }
        }
    },
    plugins: [
        /* 
        * 【移除】:webpack4里面移除了commonChunksPulgin插件
        */
        // // 独立通用模块到js/base.js
        // new webpack.optimize.CommonsChunkPlugin({
        //     name : 'common',
        //     filename : 'js/base.js'
        // }),
        // 把css单独打包到文件里
        new ExtractTextPlugin("css/[name].css"),
        // html模板的处理
        new HtmlWebpackPlugin(getHtmlConfig('index', '首页')),
        new HtmlWebpackPlugin(getHtmlConfig('list', '商品列表')),
        new HtmlWebpackPlugin(getHtmlConfig('detail', '商品详情')),
        new HtmlWebpackPlugin(getHtmlConfig('cart', '购物车')),
        new HtmlWebpackPlugin(getHtmlConfig('order-confirm', '订单确认')),
        new HtmlWebpackPlugin(getHtmlConfig('order-list', '订单列表')),
        new HtmlWebpackPlugin(getHtmlConfig('order-detail', '订单详情')),
        new HtmlWebpackPlugin(getHtmlConfig('payment', '订单支付')),
        new HtmlWebpackPlugin(getHtmlConfig('user-login', '用户登录')),
        new HtmlWebpackPlugin(getHtmlConfig('user-register', '用户注册')),
        new HtmlWebpackPlugin(getHtmlConfig('user-pass-reset', '找回密码')),
        new HtmlWebpackPlugin(getHtmlConfig('user-center', '个人中心')),
        new HtmlWebpackPlugin(getHtmlConfig('user-center-update', '修改个人信息')),
        new HtmlWebpackPlugin(getHtmlConfig('user-pass-update', '修改密码')),
        new HtmlWebpackPlugin(getHtmlConfig('result', '操作结果')),
        new HtmlWebpackPlugin(getHtmlConfig('about', '关于MMall')),
    ],
    /* 
    * 【新增】:在v1.0.1版本中新增了devServer的配置,用自带的代理就可以访问接口
    */
    devServer: {
        port: 8088,
        inline: true,
        proxy : {
            '**/*.do' : {
                target: 'http://test.happymmall.com',
                changeOrigin : true
            }
        }
    }

};

module.exports = config;
点击查看更多内容
45人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
1.2万
获赞与收藏
1371

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消