学一点Webpack配置:Webpack的优化

特别声明:为感谢社区广大朋友对小站的支持,自2019年10月1日至2019年11月11日开通年费VIP通道,年费价格为 ¥299.00元。如果您喜欢小站的内容,可以点击开通会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!(^_^)

上一篇中花了14小节主要和大家一起探讨了Webpack 4.x的一些基本配置,比如初始化项目,添加各种Loader、React、Typescript、Sass、PostCSS、CSS Modules等配置、图片加载、字体加载以及各种代码检测的能力,比如ESLint的配置、Prettier的配置和StyleLint的配置。在接下来这个部分,主要和大家一起来探讨Webpack 4.x中的一些优化方面的配置。比如开发环境的优化、Webpack自身的优化、文件压缩和依赖监控以及应用分析相关的配置。如果感兴趣的话,欢迎继续往下阅读。

在阅读接下来的内容之前,如果你没有阅读上一篇,建议你先花点时间阅读上一篇,这样会更有系统性的学习

Step15:开发环境优化

请把分支切换到step15查看代码

开启局部模块热重载

在这一节中我们来对基本环境做一些优化。在开发环境中引入webpack.HotModuleReplacementPlugin用于启用局部模块热重载,方便我们开发。

我们在Step03中将Webpack的环境分离出来了,有关于Webpack开发环境的配置都将在webpack.dev.js做调整。如果我们要在开发环境加上webpack.HotModuleReplacementPlugin就需要在webpack.dev.jsplugins来做调整:

// ...

module.exports = merge(commonConfig, {
    // ...

    // 开发环境下需要的相关插件配置
    plugins: [new webpack.HotModuleReplacementPlugin()],

    // ...
});

另外在devServer也做一些调整:

// 开发服务器
devServer: {
    hot: true, // 热更新,无需手动刷新
    contentBase: DIST_PATH, //
    host: '0.0.0.0', // host地址
    port: 8080, // 服务器端口
    historyApiFallback: true, // 该选项的作用所用404都连接到index.html
    overlay: {
        // 当出现编译错误或警告时,就在页面上显示一层黑色的背景层和错误信息
        errors: true,
    },
    inline: true,
},

使用静态资源路径

网页中总是会使用到一些静态资源,将这些静态资源部署到CDN服务上,使用得用户可以就近访问资源,加快访问速度。在Webpack中,我们可以通过publicPatch来配置CDN服务器对应的URL

就我们这个工程而言,可以在webpack.common.jsoutput中指定publicPath

// webpack.common.js

// 编译输出的JS入路径
// 告诉Webpack在哪里输出它所创建的bundle,以及如何命名这些文件
output: {
    path: DIST_PATH, // 创建的bundle生成到哪里
    filename: '[name].bundle.js', // 创建的bundle的名称
    sourceMapFilename: '[name].js.map', // 创建的SourceMap的文件名
    publicPath: '/', // 指定存放静态资源的CDN地址
},

为导出的JS文件添加hash

当我们修改代码,bundle被重新打包,很可能在客户端上看到的效果并不是最新的效果,这有可能是缓存所造成的,有的时候需要多次刷新浏览器,甚至是要手动去清除缓存。不管是在开发环境还是生产环境,这直接影响我们的开发效率。在Webpack中我们可以很轻易的解决这个问题。只需要在输出的JS文件上加上hash值,这样一来,每次输出的JS文件名都会不同,那么文件也就不会被缓存。

只需要在outputfilename值上添加hash值:

// webpack.common.js

output: {
    path: DIST_PATH, // 创建的bundle生成到哪里
    filename: '[name].bundle.[hash].js', // 创建的bundle的名称
    sourceMapFilename: '[name].js.map', // 创建的SourceMap的文件名
    publicPath: '/', // 指定存放静态资源的CDN地址
},

输出的bundle.js会每次都带上相应的hash值:

注意,如果你在Webpack配置中使用了webpack.HotModuleReplacementPlugin()的话,那么在output.filename中的值不能使用[chunkhash],只能使用[hash]

这样一来每次修改代码都会生成一个带hash的JS文件。要是你执行npm run build同样会这样,并且会让你项目中/dist目录下有关于bundle.js的文件会越来越多,比如:

编译前清理dist目录

上一节我们看到了,每次都会为bundle.js新增文件,如果多次修改,再次编译或打包就会在/dist目录下生成一堆的JS文件,但上一次打包的文件对于我们来说没有实际用处。因此,我们需要在每次打包时清除/dist目录下的旧文件。

实现该功能,可以借助Webpack的CleanWebpackPlugin来实现,在配置之前先安装该插件:

⇒  npm i clean-webpack-plugin -D

然后webpack.common.js中添加相应的配置:

// webpack.common.js
// 注意最新版本引用CleanWebpackPlugin 不能使用 const CleanWebpackPlugin = require('clean-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    // ...

    // 模块解析
    module: {
        rules: [
        // ...
        ]

    // 插件
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            inject: true,
            template: HtmlWebpackTemplate,
            appMountId: 'root',
            filename: 'index.html',
        }),
    ],
};

另外一个细节,如果配置中同时出现CleanWebpackPluginHtmlWebpackPlugin时,CleanWebpackPlugin需要放置在HtmlWebpackPlugin的前面。

配置完成之后,你在命令终端执行npm run build的时候,/dist目录下中以前的bundle.js会自动清除。

这里额外提一下,在HtmlWebpackPlugin的配置中我们可以添加minify相关的配置,这样会将打包生的.js.css文件引入到.html文件中:

// webpack.common.js
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        inject: true,
        template: HtmlWebpackTemplate,
        appMountId: 'root',
        filename: 'index.html',
        minify: {
            removeComments: true, // 去掉注释
            collapseWhitespace: true, // 去掉多余空白
            removeAttributeQuotes: true, // 去掉一些属性的引号,例如id="moo" => id=moo
        },
    }),
],

有了上面的配置之后,在代码中的注释、空白等就会自动清除,比如App.tsx中的注释:

<!-- App.tsx -->
<div style={{ textAlign: 'center' }}>
    <img src={String(Security)} />
    {/* 下面这样引用,图片会报404错误 */}
    {/* <img src="../../../../assets/images/security.svg" alt=""/> */}
</div>

编译出来.html中就看不到了。如下图所示:

Step16:Webpack的优化

请把分支切换到step16查看代码

在这一步我们主要来一起探讨Webpack中的一些优化。

文件路径优化

在Webpack中我们配置了resolve.extension之后可以不用在requireimport的时候加文件扩展名,Webpack会依次尝试添加扩展名进行匹配。在resolve中还可以通过alias来配置别名,可以加快Webpack查找模块的速度。

// webpack.common.js

alias: {
    '@': path.resolve(__dirname, '../src'),
    '@components': path.resolve(__dirname, '../src/components'),
    '@pages': path.resolve(__dirname, '../src/pages'),
    '@images': path.resolve(__dirname, '../src/assets/images'),
    '@fonts': path.resolve(__dirname, '../src/assets/fonts'),
    '@icons': path.resolve(__dirname, '../src/assets/icons'),
},

在实际使用的时候,我们就可以使用定义好的别名了:

<!-- App.tsx -->
const Security = require('@images/security.svg');

// app.css
body {
    background: url("~@images/body-background.jpg") no-repeat center,
        linear-gradient(to bottom, #f560a9, #09aefa, #2390af) no-repeat center;
}

有一点需要特别注意,在TypeScript环境下,如果仅在Webpack中配置别名是不够的,比如:

<!-- App.tsx -->
import Button from '@components/Button/Button';

编译的时候会报错:

Failed to compile.

[at-loader] ./src/pages/index/components/App/App.tsx:5:20 
    TS2307: Cannot find module '@components/Button/Button'.

我们需要在tsconfig.json中添加paths的配置:

{
    "compilerOptions": {
        "sourceMap": true,
        "noImplicitAny": false,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "module": "es2015",
        "target": "es6",
        "lib": [
            "es2015",
            "es2017",
            "dom"
        ],
        "removeComments": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "moduleResolution": "node",
        "pretty": true,
        "jsx": "preserve",
        "allowJs": true,
        "baseUrl": ".",
        "rootDir": "./src",
        "outDir": "./dist/",
        "paths": {
            "@/*": ["./src/*"],
            "@components/*": ["./src/components/*"],
            "@pages/*": ["./src/pages/*"],
            "@images/*": ["./src/assets/images/*"],
            "@fonts/*": ["./src/assets/fonts/*"],
            "@icons/*": ["./src/assets/icons/*"],
        }
    },
    "include": ["./src/**/*"],
    "exclude": ["node_modules"]
}

上面的问题就解决了。

优化CSS文件

如果不做相关的配置,打包的时候CSS代码会直接打到JavaScript文件中。在Webpack中使用MiniCssExtractPlugin插件可以单独生成.css文件。这样CSS和JavaScript文件可以并行下载,提高页面加载性能。

先安装mini-css-extract-plugin

⇒  npm i mini-css-extract-plugin -D

由于MiniCssExtractPlugin插件还不支持HMR,为了不影响开发效率,因为需要对开发环境做一下判断。目前有两种方式:

  • webpack.common.js中有关于样式的配置分开到webpack.dev.jswebpack.prod.js中分别处理,在webpack.prod.js中配置MiniCssExtractPlugin插件
  • webpack.common.js中通过process.env.NODE_ENV的值来做判断,如果值为production时才配置MiniCssExtractPlugin插件

在这里我们采用第二种方式:

// webpack.common.js

// ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
// ...

// 模块解析
module: {
    rules: [
        // ...

        // CSS Loader
        {
            test: /\.(sc|sa|c)ss$/,
            exclude: /node_modules/,
            include: path.resolve(__dirname, '../src'),
            use: [
                {
                    loader: process.env.NODE_ENV !== 'dev' ? MiniCssExtractPlugin.loader : 'style-loader',
                    options: {
                        sourceMap: true,
                    },
                },
                {
                    loader: 'css-modules-typescript-loader',
                    options: {
                        named
剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/javascript/webpack-config-part2.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部