专栏首页前端技术总结升级你的webpack(下)-- webpack入门教程(三)
原创

升级你的webpack(下)-- webpack入门教程(三)

背景介绍:

我负责的一个前端项目之前用到的是webpack1,现需要升级到webpack4,特此记录下升级过程中有一些配置和需要注意的问题,具体会介绍:

(1) 需要的node环境的升级

(2) mode参数切换开发模式还是生产模式

(3) 移除了CommonsChunkPlugin,改用了optimization属性进行更加灵活的配置

(4) 用新的CSS文件提取插件mini-css-extract-plugin,替换extract-text-webpack-plugin

由于篇幅较长,分为上下两篇介绍,本文主要介绍后面两点,关于前面两点的介绍,请移步升级你的webpack(上)-- webpack入门教程(二)

1.使用optimization,替代了CommonsChunkPlugin

1.1 持久化缓存

webpack需要使用hash来做静态资源的更新,文件名的hash值目前有三种计算hash的方式:[hash]、[chunkhash]以及[contenthash]。

区别:

[hash]:每次webpack在编译的过程中会生成唯一的hash值,项目中任何一个文件改动后就会被重新创建,然后webpack会计算新的hash值。简单来说,hash是跟整个项目的构建相关,每一次构建就生成一个hash值,即使文件内容没有改变。

[chunkhash]:根据模块计算出来的hash值,所以某个文件的改动只会影响自己的hush值,而不会影响到其他文件的hash值。

[contenthash]:由文件内容产生的hash值,内容不同产生的contenthash值就不一样。

如果项目中是把所有的内容都打包成同一个文件,那么[hash]就足够了。而如果项目中涉及到拆包、分模块进行加载等,那么需要用到[chunkhash],来保证每次更新后,只有改变的相关文件的hash值发生改变。

module.exports = {
    entry: {
        index: [
            path.resolve(__dirname, './modules/index.js')
        ]
    },
    output: {
        path: path.resolve(__dirname, '../../app/public/v2'), 
        filename: 'js/[name].[chunkhash:8].js',
    }
}

上述代码的意思是:以index.js为入口文件,将所有的代码全部打包到一个文件名为index.xxxx.js,并放到app/public/v2/js目录下,这样每次更新代码时会生成新的命名文件了。

但这样只能应付简单的场景,在大型多页面应用中,往往需要对页面进行优化,涉及拆包、分模块加载:

(1)分离业务代码和第三方的代码:之所以将业务代码和第三方代码分离出来,是因为业务代码更新频率高,而第三方代码更新迭代速度慢,所以我们将第三方代码(库,框架)进行抽离,这样可以充分利用浏览器的缓存来加载第三方库。

(2)按需加载:比如在使用 react-router 的时候,当用户需要访问到某个路由的时候再去加载对应的组件,那么用户没有必要在一开始的时候就将所有的路由组件下载到本地。

(3)在多页面应用中,我们往往可以将公共模块进行抽离,比如 header, footer 等等,这样页面在进行跳转的时候这些公共模块因为存在于缓存里,就可以直接进行加载了,而不是再进行网络请求了。

那么如何进行拆包,分模块进行加载呢?

在webpack4之前,可以使用webpack 内置插件:CommonsChunkPlugin。从webpack4开始,optimization

替代了CommonsChunkPlugin插件,改用optimization属性进行更加灵活的配置。

1.2 使用optimization属性,替代CommonsChunkPlugin

每个配置项的作用:

-- minSize 

分离前的最小块文件大小,单位为字节

-- minChunks

分离前该块被引入的次数

-- maxInitialRequests

一个入口文件可以并行加载的最大文件数量

-- maxAsyncRequests

内层文件(第二层)按需加载时最大的并行加载数量

-- name

用以控制分离后代码块的命名,若不存在则为  [来源]~[入口的key值].js 的格式

-- automaticNameDelimiter

修改上文中的 “~” ,  若改为: “-” 则分离后的js默认命名规则为 [来源]-[入口的key值].js

-- test

用来控制哪些模块被缓存组选择,test: /node_modules/  即为匹配相应文件夹下的模块

-- cacheGroups

缓存组,其实就是存放分离代码块的规则的对象。如果不希望使用默认配置,可以通过splitChunks.cacheGroups进行配置,cacheGroup中priority 为分离规则的优先级,优先级越高,则优先匹配。

-- chunks

匹配的块的类型:initial(初始块),async(按需加载的异步块),all(所有块)

-- priority

这个配置很重要,即便是所有配置项都写好了,优先级不够,或者优先级设置不正确,也得不到相应的结果。当需要优先匹配缓存组的规则时,priority需要设置为正数,当需要优先匹配默认设置时,缓存组需设置为负数,0为两者的分界点。

更多的配置项可参看webpack官方文档以下是optimize.splitChunks 中的一些配置参考:

module.exports = {
    optimization: {
        runtimeChunk: {
            name: 'manifest'
        },
        //webpack4不再需要UglifyJsPlugin,设定optimization.minimizer为true即可
        //production mode下面自动为true
        minimizer: true,
        splitChunks: {
            chunks: 'async',
            minSize: 30000,
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            name: false,
            cacheGroups: {
                vendor: {
                    name: 'vendor',
                    chunks: 'initial',
                    priority: -10,
                    reuseExistingChunk: false,
                    test: /node_modules\/(.*)\.js/
                },
                //将多个css chunk合并成一个css文件
                styles: {
                    name: 'styles',
                    test: /\.(scss|css)$/,
                    chunks: 'all',
                    minChunks: 1,
                    reuseExistingChunk: true,
                    enforce: true
                }
            }
        }
    }
}

说明:

(1) CommonsChunkPlugin需要通过配置两次new webpack.optimize.CommonsChunkPlugin来分别获取vendor和manifest的通用chunk方式已经做了整合, 直接在optimization中配置splitChunks和runtimeChunk即可 ,提取功能也更为强大。

(2) runtimeChunk可以配置成true、single或者对象,用于自动计算当前构建的一些基础chunk信息,类似之前版本中的manifest信息获取方式。

(3) webpack.optimize.UglifyJsPlugin现在不需要了,只需要使用optimization.minimizer为true即可,production mode下面自动为true,当然如果想使用第三方的压缩插件也可以在optimization.minimizer的数组列表中进行配置,例如这样配置:

//在optimization.minimizer的数字列表中配置,使用第三方的压缩插件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

config.optimization = {
    minimizer: [
        new UglifyJsPlugin({
            cache: true,
            parallel: true
        }),
        new OptimizeCSSPlugin({
            cssProcessorOptions: {
                autoprefixer: { disable: true },
                discardComments: {
                    removeAll: true,
                },
                canPrint: true
            }
        })
    ],
};

2.使用mini-css-extract-plugin,替代了extract-text-webpack-plugin

优点:

没有重复编译,性能比原来要好

异步加载,当js文件被异步加载时,需要的css文件也会自动加载

因为只针对css文件,所以自动带了一些优化,比如在mode:production时,自动minify

webpack1使用extract-text-webpack-plugin,基本配置如下:

//webpack1用extract-text-webpack-plugin:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    module: {
        loaders: [
            {
                test: /\.less$/,
                loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
            },
        ]
    },

    plugins: [
        new ExtractTextPlugin("css/[name].[chunkhash].css"),
    ]
}

webpack4使用mini-css-extract-plugin,基本配置如下:

//webpack4用mini-css-extract-plugin:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    module: {
        rules: [
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'less-loader'
                ]
            },
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "css/[name].[chunkhash].css"
        }),
    ]
}

3.小结

本文详细介绍了项目中从webpack1升级到webpack4时一些需要注意的配置,如有问题,欢迎指正。

以下是webpack系列的往期文章:

超详细!webpack入门教程(一)

升级你的webpack(上)-- webpack入门教程(二)

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 超详细!webpack入门教程(一)

    前端构建工具就是把开发环境的代码转化成运行环境代码。一般来说,开发环境的代码是为了更好的阅读,而运行环境的代码则是为了能够更快地执行。因此开发环境和运行环境的代...

    前端林子
  • 小结ES6基本知识点(四):数组的扩展

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门

    前端林子
  • 详解CSS的Flex布局

    Flex是Flexible Box 的缩写,意为"弹性布局",是CSS3的一种布局模式。通过Flex布局,可以很优雅地解决很多CSS布局的问题。下面会分别介绍容...

    前端林子
  • 字符串分拆函数

    在Oracle中,如果一个包含分隔符的字符串(比如说“55*62*77”,这个字符串是用*号做分隔符,可以拆分成三个数“55”,“62”和“77”),要将它们拆...

    源哥
  • 前端-手摸手,带你用合理的姿势使用 webpack 4(上)

    前几天 webpack 作者 Tobias Koppers 发布了一篇新的文章:webpack 4.0 to 4.16: Did you know?,总结了一下...

    grain先森
  • 【玩转腾讯云】Laravel gulp

    gyp ERR! stack Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modu...

    无忧366
  • IDEA快速入门(Mac版)

    【持续更新】一篇今年年头的老文章顺道发布了,大家有任何问题可以留言沟通。当时刚刚加入团团,愿大家有机会还是购买一台MAC,确实能给大家的效率赋能,虽然在一开始会...

    用户1216676
  • intellij idea 常用快捷键mac版

    login.jsp文件中的html标签都是大写格式的,看着很不舒服,就改了一下,全部用的快捷键修改成小写的,也因此整理了一下常用的快捷键。 shift + Co...

    我是十三
  • BigData--大数据分析引擎Spark

    (1)zeroValue:给每一个分区中的每一个key一个初始值; (2)seqOp:函数用于在每一个分区中用初始值逐步迭代value; (3)combO...

    MiChong
  • 程序员不能错过的20个学习网站

    这个假期过得尤其漫长,还得时不时地提防一觉醒来,假期延长的消息到来。好在,现在情况越来越好,很多地方都紧锣密鼓地进入了正轨,比如我已经通过一周的远程办公,一周的...

    程序员小跃

扫码关注云+社区

领取腾讯云代金券