升级 webpack 至 v2.2.x

本文主要讲述如何将 webpack 版本升级至 v2.2.x,如果你还不了解 webpack,那么推荐你先读一下这篇文章

今年年初,webpack 2.2.0 版本正式发布,还记得那时已有很多文章来介绍 webpack 2。 但经历过之前,先将默认安装升级至 2.0.x-beta 又退回 1.x 的我来说,吃一堑长一智,决定先观察看看。

经过这几个月的时间,并没有什么大新闻发生,应该不会再闹乌龙了,便把公司项目和自己博客都试着升级一波看看效果。

为什么要升级至 Webpack2

你可能会问 webpack1 用得好好的为啥要去升级成 webpack 2 哪?有啥好处?是不是又在瞎折腾了?

当然不是在瞎折腾,因为 webpack2 最大一个好处就是 Tree Shaking(摇树),这也是年初 webpack2 火了一把的最大原因。

使用 webpack2 还有没有其他好处哪?当然是有的。

除了 Tree Shaking 之外,webpack2 还支持了 ES6 的模块语法,单就这一点已经不需要 babel 了,当然如果你要用其他一些新特性,还是得加入 babel-loader。

与此同时,webpack2 还支持使用 System.import 来动态加载模块。不过,使用此功能时要注意,对不支持 Promise 的浏览器需要添加 polyfill。

再加之,webpack 已经正式弃用 webpack1,也就不再维护了。从长期的角度考虑,升级到 webpack2 也更加稳妥。

知道了为啥升级,接着就来看看如何升级。

主要变化和注意点

如何从 v1 升级至 v2,webpack 官网的升级手册已经介绍的非常详细了,基本先过一遍,然后遇到问题再搜索一下就能搞定。(英文不好的童鞋也不用担心,已经有人翻译了中文版

这里就不再一一赘述升级变更点了,主要按常用功能整理、分享一下 webpack2 升级的变化。

首先,来看看升级前的配置文件。(由于篇幅原因省略了一些重复性的配置,有兴趣的可以到 Github 上查看详细内容

// base.js
const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const SOURCE_PATH = path.join(__dirname, '../../src');
const DIST_PATH = path.join(__dirname, '../../build/client');

const webpackConfig = {
    // http://mp.weixin.qq.com/s?__biz=MzI3NTE2NjYxNw==&mid=2650600472&idx=1&sn=d4bf85c1bb26a32aff144e81d652582f
    devtool: 'source-map',
    output: {
        path: DIST_PATH,
        publicPath: '/'
    },
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js',
            'assets': SOURCE_PATH + '/client/assets',
            // 省略其他 alias...
        },
        extensions: ['', '.js']
    },
    eslint: {
        configFile: '.eslintrc',
        emitWarning: true,
        emitError: true,
        formatter: require('eslint-friendly-formatter')
    },
    postcss: [autoprefixer({browsers: ['last 2 versions']})],
    plugins: [
        new ExtractTextPlugin('style-[contenthash:8].css'),
        new webpack.NoErrorsPlugin()
    ],
    module: {
        preLoaders: [
            {
                test: /[^(\.min)]\.js$/,
                loader: 'eslint-loader',
                exclude: /node_modules/,
                include: SOURCE_PATH
            }
        ],
        loaders: [
            {
                test: /[^(\.min)]\.js$/,
                loaders: ['babel'],
                exclude: /node_modules/,
                include: SOURCE_PATH
            },
            {
                test: /\.html$/,
                loader: 'html',
                query: {interpolate: true},
                exclude: /node_modules/,
                include: SOURCE_PATH
            },
            {
                test: /\.(sc|c)ss$/,
                // extract css file from js file, that will reduce the js file size and optimize page loading.
                // but it will increase the package time, so it should be only used in build file.
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!sass-loader')
                // loaders: ['style', 'css', 'postcss', 'sass']
            },
            // 省略其他 loader...
        ]
    }
};

由于之前博客已升级成同构应用,webpack 的配置被分为了客户端和服务器端两套,上面这个文件便是两套配置中共通的部分。除了没有设置 entry,基本的 webpack 配置就同它差不多,升级 webpack2 也不需要修改 entry,也就正好不用列出了。

接着就一个个来看,这些基本、常用的配置属性,有哪些不要改,有哪些要改的。

一开始就是个好消息,两个属性 devtooloutput,它俩同 entry 一样不用修改。

resolve

接着是 resolveresolve 的变化也不大,主要是其中两个字段的变化,rootextensions

  • root 改为了 modules,用于设置 webpack 查询模块的路径,默认是 ["node_modules"]
    同时,搜索模块的优先级与数组的顺序有关,越靠前的越先匹配,比如 [path.resolve(__dirname, "src"), "node_modules"],此时,webpack 查找模块时会优先查找本地 src 下的模块,查不到再到 node_modules 中查找。
  • extensions,用于设置 webpack 处理的扩展名,默认值为 [".js", ".json"]
    这里就牵扯到 2 个变更点:
    1. 升级后就不用像 v1 一样添加一个空字符串 "" 了;
    2. v2 自带 json-loader 来处理 json 类型的文件,而不须我们自己手动引入。

这两个配置大部分情况下使用默认值(不配置)就可以了。但在 react 或 vue 的项目中,可能需要在 extensions 中添加 .jsx.vue

接着两个是 eslintpostcss,属于自定义属性,在 webpack2 中不支持自定义属性,需要挪到各自的 loader 中进行配置。

既然,遇到了 loader 相关,下一步就先升级 loader

module

在 webpack 中,module 下不再有 preLoaders, loaderspostLoaders 统一都变成了 rules,如需要替换 preLoaderspostLoaders 则需通过设置 rules.enforce 属性。

同时,webpack2 不再支持 loaders,改为 rules.useloader 属性可以继续使用。loader 相关的配置,可以通过 rules.use.options 设置。

还有一点,在 webpack2 中,已不再默认给 loader 添加 -loader 后缀,不过还可以通过将 resolveLoader 设置为 moduleExtensions: ["-loader"] 来给 loader 添加默认后缀。不过,webpack 官方不推荐这么做,还是为每个 loader 都加上 -loader 比较好。

这部分可以算是 webpack2 升级过程中改动量最多的地方了。但别担心,这只是个有点麻烦,细心一点就能解决的问题。

还剩下最后一个部分,plugin 在来看一下它的变化。

plugin

plugin 部分 webpack2 有着一下这些变化:

  • 新增 LoaderOptionsPlugin,用于设置全局的 loaderplugin 属性
  • 默认引入 OccurrenceOrderPlugin,也就是可以删了原先的这个配置
  • DedupePlugin 也被移除
  • NoErrorsPlugin 重命名为 NoEmitOnErrorsPlugin
  • UglifyJsPlugin 不再默认压缩 js,需在 LoaderOptionsPlugin 配置 minimize: true

这样升级就基本完成了,再来看一下修改后的配置文件。

// base.js
const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const SOURCE_PATH = path.join(__dirname, '../../src');
const PUBLIC_PATH = '/';
const DIST_PATH = path.join(__dirname, '../../build/client');

const webpackConfig = {
    // http://mp.weixin.qq.com/s?__biz=MzI3NTE2NjYxNw==&mid=2650600472&idx=1&sn=d4bf85c1bb26a32aff144e81d652582f
    devtool: 'source-map',
    output: {
        path: DIST_PATH,
        publicPath: PUBLIC_PATH
    },
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js',
            'assets': SOURCE_PATH + '/client/assets',
            // 省略其他 alias...
        }
    },
    plugins: [
        new ExtractTextPlugin('style-[contenthash:8].css'),
        new webpack.NoEmitOnErrorsPlugin()
    ],
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'eslint',
                enforce: 'pre',
                exclude: /node_modules/,
                options: {
                    emitWarning: true,
                    emitError: true,
                    formatter: require('eslint-friendly-formatter')
                }
            },
            {
                test: /\.js$/,
                loader: 'babel',
                exclude: /node_modules/
            },
            {
                test: /\.html$/,
                loader: 'html?interpolate',
                exclude: /node_modules/
            },
            {
                test: /\.(sc|c)ss$/,
                // extract css file from js file, that will reduce the js file size and optimize page loading.
                // but it will increase the package time, so it should be only used in build file.
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        'css-loader?sourceMap',
                        {
                            loader: 'postcss-loader?sourceMap',
                            options: {
                                plugins: () => [autoprefixer({browsers: ['last 2 versions']})]
                            }
                        },
                        'sass-loader'
                    ]
                })
            },
            // 省略其他 loader...
        ]
    }
};

不要以为这就完了,勿忘初心。这只是成功升级了 webpack,还没用上 Tree Shaking 哪。

Tree Shaking & Module

想要使用 webpack2 的 tree shaking 就需要让 webpack 来管理模块之间的加载,而不是让 babel-loader 去处理。

不过,这修改起来也很简单,只需修改 babel 的配置文件 .babelrc,将原先的 es2015 改为 ["es2015", { "modules": false }] 就可以了。

在公司项目升级 webpack 修改模块引入方式时,还遇到过 Module build failed: some file... TypeError: Cannot read property '0' of null 这样一个问题,折腾了半天。最后发现是因为 babel-plugin-antd 报出的问题,babel-plugin-antd 前一阵就升级成 babel-plugin-import 了,项目里也升级一下问题就解决了.

升级 webpack 后,记得同时升级所用到的 loader 和 plugin。

这样升级基本完成了,对比一下升级前后的打包结果。

build with webpack1
build with webpack1
build with webpack2
build with webpack2

可以看到,app.js 小了不到 8kb,减小了 10%,而 common.js 反而大了 12kb,都没改代码啊~[捂脸]

总得来说,将 webpack 从 v1 升级至 v2,主要修改 resolve, moduleplugin 这 3 个属性,而且基本是一些字段名的修改,整体结构上没有大的变化,升级还是比较简单的,是个耐心活。

至此,博客 2 代成员(vue2 和 koa2)又多了一位 webpack2...😂

相关阅读:Why Webpack 2's Tree Shaking is not as effective as you think

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容