美文网首页
webpack 配置从头到脚

webpack 配置从头到脚

作者: 泉泉泉泉泉泉 | 来源:发表于2020-08-04 15:31 被阅读0次

    下面是webpack.conf.prod.js 部分内容

    const path = require("path");
    const config = {
      mode: "production",
      resolve: webpackConfigResolve,
      stats: "minimal",
      entry: './app.js';
      output: {
        filename:'bundle.js',
      },
      module: {
        rules: webpackConfigmModuleRules,
      },
      optimization: {},
      plugins: [],
    };
    

    首先认识下webpack每项配置项

    entry

    待更

    output

    待更

    module

    待更

    resolve

    webpack 在启动后会从配置的入口模块出发找出所有依赖的模块,resolve配置 webpack 如何寻找模块所对应的文件。 webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也可以根据自己的需要修改默认的规则。如下配置

    const path = require('path');
    function resolve(dir) {
      return path.join(__dirname, '..', dir);
    }
    module.exports = {
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.less', '.css'],
      mainFields: ['module', 'jsnext:main', 'main'],
      symlinks: false,
      alias: {
        '@': resolve('src'),
      },
    };
    
    • alias
      resolve.alias配置项通过别名来把原导入路径映射成一个新的导入路径。例如使用以下配置:
     resolve:{
      alias:{
        components: './src/components/'
      }
    }
    

    当你通过import Button from 'components/button导入时,实际上被 alias 等价替换成了 import Button from './src/components/button'

    以上 alias 配置的含义是把导入语句里的components关键字替换成./src/components/

    这样做可能会命中太多的导入语句,alias 还支持 $ 符号来缩小范围到只命中以关键字结尾的导入语句:

    resolve:{
      alias:{
        'react$': '/path/to/react.min.js'
      }
    }
    

    react$只会命中以react结尾的导入语句,即只会把import 'react'关键字替换成import '/path/to/react.min.js'

    • mainFields
      有一些第三方模块会针对不同环境提供几分代码。 例如分别提供采用 ES5 和 ES6 的2份代码,这2份代码的位置写在package.json文件里,如下:
    {
      "jsnext:main": "es/index.js",// 采用 ES6 语法的代码入口文件
      "main": "lib/index.js" // 采用 ES5 语法的代码入口文件
    }
    

    Webpack 会根据 mainFields 的配置去决定优先采用那份代码, mainFields 默认如下:

    mainFields: ['browser', 'main']
    

    Webpack 会按照数组里的顺序去 package.json 文件里寻找,只会使用找到的第一个
    假如你想优先采用 ES6 的那份代码,可以这样配置:

    mainFields: ['jsnext:main', 'browser', 'main']
    
    • extensions
      在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在。resolve.extensions用于配置在尝试过程中用到的后缀列表,默认是:
    extensions: ['.js', '.json']
    

    也就是说当遇到require('./data')这样的导入语句时,Webpack 会先去寻找./data.js文件,如果该文件不存在就去寻找./data.json文件, 如果还是找不到就报错。

    假如你想让 Webpack 优先使用目录下的 TypeScript 文件,可以这样配置:

    extensions: ['.ts', '.js', '.json']
    
    • modules
      resolve.modules 配置 Webpack 去哪些目录下寻找第三方模块,默认是只会去 node_modules 目录下寻找。 有时你的项目里会有一些模块会大量被其它模块依赖和导入,由于其它模块的位置分布不定,针对不同的文件都要去计算被导入模块文件的相对路径, 这个路径有时候会很长,就像这样 import ../../../components/button' 这时你可以利用modules配置项优化,假如那些被大量导入的模块都在./src/components目录下,把 modules 配置成
    modules:['./src/components','node_modules']
    

    后,你可以简单通过import 'button'导入。

    • descriptionFiles
      resolve.descriptionFiles配置描述第三方模块的文件名称,也就是 package.json 文件。默认如下:
    descriptionFiles: ['package.json']
    
    • enforceExtension
      resolve.enforceExtension如果配置为true所有导入语句都必须要带文件后缀,例如开启前import './foo'能正常工作,开启后就必须写成import './foo.js'

    • enforceModuleExtension
      enforceModuleExtensionenforceExtension 作用类似,但 enforceModuleExtension 只对 node_modules 下的模块生效。 enforceModuleExtension 通常搭配 enforceExtension 使用,在 enforceExtension:true 时,因为安装的第三方模块中大多数导入语句没带文件后缀, 所以这时通过配置 enforceModuleExtension:false 来兼容第三方模块

    plugins

    常用的plugins如下

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
    const cssnano = require("cssnano");
    const TerserPlugin = require("terser-webpack-plugin");
    const HappyPack = require("happypack");
    
    • html-webpack-plugin
      作用:生成html
    const htmlPlugin = new HtmlWebpackPlugin({
        filename: `${entry}.html`,
        title: `${titles[entry]}`,
        template: path.resolve(__dirname, '../../src/index.js'),
        chunks: [
          'vendors.core',
          'vendors.commons',
        ],
        minify: HtmlWebpackPluginMinifyOptions,
      });
    

    html-webpack-plugin插件详细用法参见:
    https://www.jianshu.com/p/08a60756ffda

    • HotModuleReplacementPlugin
      作用:页面热更新(模块热替换)
      首先我们要确保项目是基于webpack-dev-serverwebpack-dev-middle进行开发的,webpack本身的命令行并不支持HMR。webpack.conf.dev.js文件部分内容如下:
    const webpack = require('webpack');
    module.exports = {
      // ...
      plugins: [
        new webpack.HotModuleReplacementPlugin()
      ],
      devServer:{
        hot:true,
      }
    }
    

    也可以在页面中开启HMR,比如下面这个例子:

    import { add } from 'util.js';
    add(2,3);
    if(module.hot){
      module.hot.accept();
    }
    

    热更新原理:
    css-loader、vue-loader已经帮我们写了这部分代码,所以不需要手写了,但是如果是HTML,需要自己手动执行下面的代码

    if (module.hot) {
      module.hot.accept('文件地址', () => {
        // 重新执行文件
      })
    }
    
    • mini-css-extract-plugin(webpack 4及以上版本)
      mini-css-extract-plugin可以理解成extract-text-webpack-plugin的升级版,它拥有更丰富的特性和更好的性能,从Webpack 4开始官方推荐使用该插件进行样式提取(Webpack 4以前的版本是用不了的)。
      说到mini-css-extract-plugin的特性,最重要的就是它支持按需加载CSS,以前在使用extract-text-webpack-plugin的时候我们是做不到这一点的。举个例子,a.js通过import()函数异步加载了b.js,b.js里面加载了style.css,那么style.css最终只能被同步加载(通过HTML的link标签)。但是现在mini-css-extract-plugin会单独打包出一个0.css(假设使用默认配置),这个CSS文件将由a.js通过动态插入link标签的方式加载。

    在webpack.conf.prod.js中引入:

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module.exports = {
        entry: './app.js',
        output: {
            filename:'[name].js',
        },
        mode: 'development',
        module: {
            rules: [{
                test: /\.css$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath:'../',
                        },
                    },
                    'css-loader'
                ],
            }],
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: '[name].css',
                chunkFilename:'[name].css',
            })
        ]
    }
    
    • extract-text-webpack-plugin(webpack 4之前版本)
      作用:提取样式到css文件
      在webpack.conf.prod.js中引入:
    const ExtractTextplugin = require('extract-text-webpack-plugin');
    module.exports = {
      entry: './app.js';
      output: {
        filename:'bundle.js',
      },
      mode:'development',
      module: {
        rules:[
          {
            test:/\.css$/,
            use:ExtractTextplugin.extract({
              fallback:'style-loader',
              use:'css-loader',
            })
          }
        ]
      },
      plugins:[
        new ExtractTextPlugin('bundle.css')
      ]
    } 
    
    • optimize-css-assets-webpack-plugin
      作用:压缩css
      压缩CSS文件的前提是使用extract-text-webpack-plugin或mini-css-extract-plugin将样式提取出来,接着使用optimize-css-assets-webpack-plugin来进行压缩,这个插件本质上使用的是压缩器cssnano,当然我们也可以通过其配置进行切换。具体请看下面的例子:
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    module.exports = {
        // ...
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: 'css-loader',
                    }),
                }
            ],
        },
        plugins: [new ExtractTextPlugin('style.css')],
        optimization: {
            minimizer: [new OptimizeCSSAssetsPlugin({
                // 生效范围,只压缩匹配到的资源
                assetNameRegExp: /\.optimize\.css$/g,
                // 压缩处理器,默认为 cssnano
                cssProcessor: require('cssnano'),
                // 压缩处理器的配置
                cssProcessorOptions: { discardComments: { removeAll: true } },
                // 是否展示 log
                canPrint: true,
            })],
        },
    };
    
    • terser-webpack-plugin (webpack 4 集成)
      作用:压缩Javascript
    const TerserPlugin = require('terser-webpack-plugin');
    module.exports = {
        //...
        optimization: {
            // 覆盖默认的 minimizer
            minimizer: [
                new TerserPlugin({
                    /* your config */
                    test: /\.js(\?.*)?$/i,
                    exclude: /\/excludes/,
                })
            ],
        },
    };
    
    • webpack-bundle-analyzer
      作用:分析打包后输出的bundle体积大小。
      配置如下:
    const Analyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    module.exports = {
      ...
      plugins: [
        new Analyzer()
        ],
    }
    
    • clean-webpack-plugin
      作用:在每次构建前清理 /dist 文件夹。
      配置如下:
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    module.exports = {
      ...
      plugins:[
            new CleanWebpackPlugin()
      ],
    }
    

    参考博客:
    https://www.cnblogs.com/joyco773/p/9049760.html
    https://www.jianshu.com/p/755aad97d810
    https://www.jianshu.com/p/2df87e8f4d3e
    https://www.jianshu.com/p/d08d5bc85ad2

    相关文章

      网友评论

          本文标题:webpack 配置从头到脚

          本文链接:https://www.haomeiwen.com/subject/wdswrktx.html