最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • webpack配置(三)

    正文概述 掘金(蒲月阿七)   2021-02-09   624

    优化环境配置

    概述

    • 开发环境性能优化
      • 优化打包构建速度
        • HMR
      • 优化代码调试
        • source-map
    • 生产环境性能优化
      • 优化打包构建速度
        • oneOf
        • babel缓存
        • 多进程打包
        • externals
        • dll
      • 优化代码运行的性能
        • 缓存(hash-chunkhash-contenthash)
        • tree shaking
        • code split
        • 懒加载/预加载
        • pwa

    HMR (热模块替换 / 模块热替换)

    /*
      HMR: hot module replacement 热模块替换 / 模块热替换
        作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块) 
          极大提升构建速度
          
          样式文件:可以使用HMR功能:因为style-loader内部实现了
          js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码
            注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。
          html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了 (不用做HMR功能)
            解决:修改entry入口,将html文件引入
    */
    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
    	// 解决html不能热更新,引入在entry中html文件
      entry: ['./src/js/index.js', './src/index.html'],
      output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          // loader的配置
          {
            // 处理less资源
            test: /\.less$/,
            use: ['style-loader', 'css-loader', 'less-loader']
          },
          {
            // 处理css资源
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
          },
          {
            // 处理图片资源
            test: /\.(jpg|png|gif)$/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              // 关闭es6模块化
              esModule: false,
              outputPath: 'imgs'
            }
          },
          {
            // 处理html中img资源
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            // 处理其他资源
            exclude: /\.(html|js|css|less|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              name: '[hash:10].[ext]',
              outputPath: 'media'
            }
          }
        ]
      },
      plugins: [
        // plugins的配置
        new HtmlWebpackPlugin({
          template: './src/index.html'
        })
      ],
      mode: 'development',
      devServer: {
        contentBase: resolve(__dirname, 'build'),
        compress: true,
        port: 3000,
        open: true,
        // 开启HMR功能
        // 当修改了webpack配置,新配置要想生效,必须重新webpack服务
        hot: true
      }
    };
    

    注意点⚠️

    • 当修改了webpack配置,新配置要想生效,必须重新webpack服务。
    • HMR功能:一个模块发生变化,只会重新打包这一个模块,而不是打包所有模块,极大提升构建速度。
    • 样式文件可以使用HMR功能,因为style-loader内部实现了。
    • js文件默认不可以使用HMR功能,所以需要修改js代码,添加支持HMR功能的代码。HMR功能只能处理非入口js文件的其他js文件。
    • html文件默认不能使用HMR功能,而且会导致html不能热更新。解决html不能热更新的方法是修改entry入口,将html文件引入。

    source-map

    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: ['./src/js/index.js', './src/index.html'],
      output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          // loader的配置
          {
            // 处理less资源
            test: /\.less$/,
            use: ['style-loader', 'css-loader', 'less-loader']
          },
          {
            // 处理css资源
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
          },
          {
            // 处理图片资源
            test: /\.(jpg|png|gif)$/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              // 关闭es6模块化
              esModule: false,
              outputPath: 'imgs'
            }
          },
          {
            // 处理html中img资源
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            // 处理其他资源
            exclude: /\.(html|js|css|less|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              name: '[hash:10].[ext]',
              outputPath: 'media'
            }
          }
        ]
      },
      plugins: [
        // plugins的配置
        new HtmlWebpackPlugin({
          template: './src/index.html'
        })
      ],
      mode: 'development',
      devServer: {
        contentBase: resolve(__dirname, 'build'),
        compress: true,
        port: 3000,
        open: true,
        hot: true
      },
      
      // 在这里设置要用到哪种代码映射技术
      devtool: 'eval-source-map'
    };
    
    /*
      source-map: 一种提供源代码到构建后代码映射技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
    
        [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
    
        source-map:外部
          错误代码准确信息 和 源代码的错误位置
          
        inline-source-map:内联
          只生成一个内联source-map
          错误代码准确信息 和 源代码的错误位置
          
        hidden-source-map:外部
          错误代码错误原因,但是没有错误位置
          不能追踪源代码错误,只能提示到构建后代码的错误位置
          
        eval-source-map:内联
          每一个文件都生成对应的source-map,都在eval
          错误代码准确信息 和 源代码的错误位置
          eval和source-map都是webpack中devtool的配置选项,eval模式是使用eval将webpack中每个模块包裹,然后在模块末尾添加模块来源
          
        nosources-source-map:外部
          错误代码准确信息, 但是没有任何源代码信息
          
        cheap-source-map:外部
          错误代码准确信息 和 源代码的错误位置 
          只能精确到行
          debug的时候大部分人都只在意代码的行数,很少关注列数,列数就是该行代码从第一个字符开始到定位字符的位置(包括空白字符)
          
        cheap-module-source-map:外部
          错误代码准确信息 和 源代码的错误位置 
          module会将loader的source map加入
          不包含loader的sourcemap,指的是使用了诸如babel等代码编译工具时,定位到的原始代码将是经过编译后的代码位置,而非原始代码。
    
        内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
    
        开发环境:速度快,调试更友好
          速度快(eval>inline>cheap>...)
            eval-cheap-souce-map
            eval-source-map
          调试更友好  
            souce-map
            cheap-module-souce-map
            cheap-souce-map
    
          常用--> eval-source-map  / eval-cheap-module-souce-map
    
        生产环境:源代码要不要隐藏? 调试要不要更友好
          内联会让代码体积变大,所以在生产环境不用内联
          nosources-source-map 全部隐藏
          hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
    
          常用--> source-map / cheap-module-souce-map
    */
    

    注意点⚠️

    • source-map是一种提供源代码到构建后代码映射技术,如果构建后代码出错了,通过映射可以追踪源代码错误。
    • 内联和外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
    • 开发环境要求速度快,调试更友好。常用的是eval-source-mapeval-cheap-module-souce-map
    • 生产环境根据需求源代码是否需要隐藏,调试需不需要友好来进行选择。内联会让代码体积变大,所以生产环境不用内联。常用的是source-mapcheap-module-souce-map

    oneOf

    const { resolve } = require('path');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    process.env.NODE_ENV = 'production';
    
    const commonCssLoader = [
      MiniCssExtractPlugin.loader,
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          plugins: () => [require('postcss-preset-env')()]
        }
      }
    ];
    
    module.exports = {
      entry: './src/js/index.js',
      output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            enforce: 'pre',
            loader: 'eslint-loader',
            options: {
              fix: true
            }
          },
          {
          	/*
            webpack原本的loader是将每个文件都过一遍。
            比如有一个js文件 rules中有10个loader,第一个是处理js文件的loader,当第一个loader处理完成后webpack不会自动跳出,而是会继续拿着这个js文件去尝试匹配剩下的9个loader,相当于没有break。
            oneOf就相当于这个break
            */
            // 以下loader只会匹配一个
            // 注意:不能有两个配置处理同一种类型文件
            oneOf: [
              {
                test: /\.css$/,
                use: [...commonCssLoader]
              },
              {
                test: /\.less$/,
                use: [...commonCssLoader, 'less-loader']
              },
              {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: {version: 3},
                        targets: {
                          chrome: '60',
                          firefox: '50'
                        }
                      }
                    ]
                  ]
                }
              },
              {
                test: /\.(jpg|png|gif)/,
                loader: 'url-loader',
                options: {
                  limit: 8 * 1024,
                  name: '[hash:10].[ext]',
                  outputPath: 'imgs',
                  esModule: false
                }
              },
              {
                test: /\.html$/,
                loader: 'html-loader'
              },
              {
                exclude: /\.(js|css|less|html|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
                  outputPath: 'media'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: 'css/built.css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        })
      ],
      mode: 'production'
    };
    

    注意点⚠️

    • 使用oneOf根据文件类型加载对应的loader,只要能匹配一个即可退出,相当于break。

    babel缓存

    const { resolve } = require('path');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    /*
      缓存:
        babel缓存
          cacheDirectory: true
          --> 让第二次打包构建速度更快
        文件资源缓存
          hash: 每次wepack构建时会生成一个唯一的hash值。
            问题: 因为js和css同时使用一个hash值。
              如果重新打包,会导致所有缓存失效。(可能我只改动一个文件)
          chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
            问题: js和css的hash值还是一样的
              因为css是在js中被引入的,所以同属于一个chunk
          contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样    
          --> 让代码上线运行缓存更好使用
    */
    
    process.env.NODE_ENV = 'production';
    
    const commonCssLoader = [
      MiniCssExtractPlugin.loader,
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          plugins: () => [require('postcss-preset-env')()]
        }
      }
    ];
    
    module.exports = {
      entry: './src/js/index.js',
      output: {
        // js资源缓存 
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            enforce: 'pre',
            loader: 'eslint-loader',
            options: {
              fix: true
            }
          },
          {
            oneOf: [
              {
                test: /\.css$/,
                use: [...commonCssLoader]
              },
              {
                test: /\.less$/,
                use: [...commonCssLoader, 'less-loader']
              },
              {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: { version: 3 },
                        targets: {
                          chrome: '60',
                          firefox: '50'
                        }
                      }
                    ]
                  ],
                  // 开启babel缓存
                  // 第二次构建时,会读取之前的缓存
                  cacheDirectory: true
                }
              },
              {
                test: /\.(jpg|png|gif)/,
                loader: 'url-loader',
                options: {
                  limit: 8 * 1024,
                  name: '[hash:10].[ext]',
                  outputPath: 'imgs',
                  esModule: false
                }
              },
              {
                test: /\.html$/,
                loader: 'html-loader'
              },
              {
                exclude: /\.(js|css|less|html|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
                  outputPath: 'media'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          // css资源缓存
          filename: 'css/built.[contenthash:10].css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        })
      ],
      mode: 'production',
      devtool: 'source-map'
    };
    

    注意点⚠️

    • 设置cacheDirectory: true进行babel缓存,让第二次打包构建速度更快。
    • 每次wepack构建时会生成一个唯一的hash值。因为js和css同时使用一个hash值,所以改动一个文件重新打包会导致所有缓存失效。
    • chunkhash是根据chunk生成的hash值。打包来源于同一个chunk,chunkhash值就一样。因为css是在js中被引入的,属于同一个chunk,所以js和css的hash值还是一样的。
    • contenthash是根据文件的内容生成hash值。不同文件hash值一定不一样。

    tree shaking

    webpack配置(三)

    ------------- package.json
    
    /*
      tree shaking:去除无用代码
        前提:1. 必须使用ES6模块化  2. 开启production环境
        作用: 减少代码体积
    
        在package.json中配置 
          "sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
            问题:可能会把css / @babel/polyfill (副作用)文件干掉
          "sideEffects": ["*.css", "*.less"]
    */
    {
    
    // 其他配置
        
      "sideEffects": [
        "*.css"
      ]
    }
    

    注意点⚠️

    • tree-shaking作用是去除无用代码,减少代码体积。
    • 使用时在package.json中配置"sideEffects": false,所有代码都可以进行tree-shaking,但是可能会把css / @babel/polyfill 等文件干掉,所以得设置成"sideEffects": ["*.css", "*.less"]才能输出相应的css、less文件。

    code split

    --------------  webpack.config.js (第一种)
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      // 单入口:单页面应用
      // entry: './src/js/index.js',
      entry: {
        // 多入口:有一个入口,最终输出就有一个bundle     多页面应用
        index: './src/js/index.js',
        test: './src/js/test.js'
      },
      output: {
        // [name]:取文件名
        filename: 'js/[name].[contenthash:10].js',
        path: resolve(__dirname, 'build')
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        })
      ],
      mode: 'production'
    };
    
    --------------  webpack.config.js (第二种)
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      // 单入口
      // entry: './src/js/index.js',
      entry: {
        index: './src/js/index.js',
        test: './src/js/test.js'
      },
      output: {
        // [name]:取文件名
        filename: 'js/[name].[contenthash:10].js',
        path: resolve(__dirname, 'build')
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        })
      ],
      /*
        1. 可以将node_modules中代码单独打包一个chunk最终输出
        2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
      */
      optimization: {
        splitChunks: {
          chunks: 'all'
        }
      },
      mode: 'production'
    };
    
    --------------  index.js (第三种)
    function sum(...args) {
      return args.reduce((p, c) => p + c, 0);
    }
    
    /*
      通过js代码,让某个文件被单独打包成一个chunk
      import动态导入语法:能将某个文件单独打包
    */
    import(/* webpackChunkName: 'test' */'./test')
      .then(({ mul, count }) => {
        // 文件加载成功
        // eslint-disable-next-line
        console.log(mul(2, 5));
      })
      .catch(() => {
        // eslint-disable-next-line
        console.log('文件加载失败~');
      });
    
    // eslint-disable-next-line
    console.log(sum(1, 2, 3, 4));
    

    注意点⚠️

    • code split能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
    • 单入口只输出一个文件,多入口可以输出多个文件。
    • 可以在webpack.config.js中设置optimization: {splitChunks: {chunks: 'all'}}将node_modules中代码单独打包一个chunk最终输出。作用是当第三方库被多个js引用时,会自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独一个chunk,减少代码体积。
    • 也可以通过在js文件中运用import动态导入语法,将某个文件单独打包成一个chunk。可以通过设置webpackChunkName: 'test'修改打包的文件名称。

    lazy loading

    ---------- test.js
    
    console.log('test.js文件被加载了~');
    
    export function mul(x, y) {
      return x * y;
    }
    
    export function count(x, y) {
      return x - y;
    }
    
    
    ---------- index.js
    
    console.log('index.js文件被加载了~');
    
    // import { mul } from './test';
    
    document.getElementById('btn').onclick = function() {
      // 懒加载:当文件需要使用时才加载
      import(/* webpackChunkName: 'test').then(({ mul }) => {
        console.log(mul(4, 5));
      });
      // 预加载 prefetch:会在使用之前,提前加载js文件 
        import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
        console.log(mul(4, 5));
      });
      
      // 正常加载可以认为是并行加载(同一时间加载多个文件)  
      // 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
    
    };
    

    注意点⚠️

    • 懒加载是指当文件需要使用时才加载。预加载指的是使用之前提前加载。正常加载可以认为是并行加载,同一时间加载多个js文件。
    • 使用懒加载的好处是在需要的时候再去加载资源,但是有时候需要加载的文件太大,可能会在需要时候的时候由于加载出现延迟,这时候预加载的好处就体现了,它会在其他资源加载完毕,浏览器空闲的时候偷偷加载资源。

    pwa

    const { resolve } = require('path');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    // 引入插件
    const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
    
    /*
      PWA: 渐进式网络开发应用程序(离线可访问)
        workbox --> workbox-webpack-plugin
    */
    
    process.env.NODE_ENV = 'production';
    
    const commonCssLoader = [
      MiniCssExtractPlugin.loader,
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          plugins: () => [require('postcss-preset-env')()]
        }
      }
    ];
    
    module.exports = {
      entry: './src/js/index.js',
      output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            enforce: 'pre',
            loader: 'eslint-loader',
            options: {
              fix: true
            }
          },
          {
            oneOf: [
              {
                test: /\.css$/,
                use: [...commonCssLoader]
              },
              {
                test: /\.less$/,
                use: [...commonCssLoader, 'less-loader']
              },
              {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: { version: 3 },
                        targets: {
                          chrome: '60',
                          firefox: '50'
                        }
                      }
                    ]
                  ],
                  cacheDirectory: true
                }
              },
              {
                test: /\.(jpg|png|gif)/,
                loader: 'url-loader',
                options: {
                  limit: 8 * 1024,
                  name: '[hash:10].[ext]',
                  outputPath: 'imgs',
                  esModule: false
                }
              },
              {
                test: /\.html$/,
                loader: 'html-loader'
              },
              {
                exclude: /\.(js|css|less|html|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
                  outputPath: 'media'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: 'css/built.[contenthash:10].css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        }),
        new WorkboxWebpackPlugin.GenerateSW({
          /*
            1. 帮助serviceworker快速启动
            2. 删除旧的 serviceworker
    
            生成一个 serviceworker 配置文件~
          */
          clientsClaim: true,
          skipWaiting: true
        })
      ],
      mode: 'production',
      devtool: 'source-map'
    };
    
    ------------- index.js
    
    import { mul } from './test';
    import '../css/index.css';
    
    function sum(...args) {
      return args.reduce((p, c) => p + c, 0);
    }
    
    // eslint-disable-next-line
    console.log(mul(2, 3));
    // eslint-disable-next-line
    console.log(sum(1, 2, 3, 4));
    
    /*
      1. eslint不认识 window、navigator全局变量
        解决:需要修改package.json中eslintConfig配置
          "env": {
            "browser": true // 支持浏览器端全局变量
          }
       2. sw代码必须运行在服务器上
          --> nodejs
          -->
            npm i serve -g
            serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
    */
    // 注册serviceWorker
    // 处理兼容性问题
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker
          .register('/service-worker.js')
          .then(() => {
            console.log('sw注册成功了~');
          })
          .catch(() => {
            console.log('sw注册失败了~');
          });
      });
    }
    

    注意点⚠️

    • PWA是渐进式网络开发应用程序(离线可访问)。需要安装workbox-webpack-plugin插件
    • new WorkboxWebpackPlugin.GenerateSW({clientsClaim: true, skipWaiting: true})两个配置帮助serviceworker快速启动以及删除旧的 serviceworker后生成一个 serviceworker 配置文件。
    • 在index.js文件中注册serviceworker,serviceworker有兼容性问题,需要进行处理。注册成功后,当无法进行网络请求时,可以通过serviceworker访问之前的离线资源。
    • 在注册serviceworker时,要注意eslint不认识 window、navigator全局变量,解决方法是修改package.json中eslintConfig配置,"env": {"browser": true},支持浏览器全局变量。同时注意sw代码必须运行在服务器上。

    多进程打包

    const { resolve } = require('path');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
    
    process.env.NODE_ENV = 'production';
    
    const commonCssLoader = [
      MiniCssExtractPlugin.loader,
      'css-loader',
      {
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          plugins: () => [require('postcss-preset-env')()]
        }
      }
    ];
    
    module.exports = {
      entry: './src/js/index.js',
      output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            enforce: 'pre',
            loader: 'eslint-loader',
            options: {
              fix: true
            }
          },
          {
            oneOf: [
              {
                test: /\.css$/,
                use: [...commonCssLoader]
              },
              {
                test: /\.less$/,
                use: [...commonCssLoader, 'less-loader']
              },
              {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                // 放在某个loader后面就会对某个loader开启多进程打包。
                  /* thread-loader
                    开启多进程打包。 
                    进程启动大概为600ms,进程通信也有开销。
                    只有工作消耗时间比较长,才需要多进程打包
                  */
                  {
                    loader: 'thread-loader',
                    options: {
                      workers: 2 // 进程2个
                    }
                  },
                  {
                    loader: 'babel-loader',
                    options: {
                      presets: [
                        [
                          '@babel/preset-env',
                          {
                            useBuiltIns: 'usage',
                            corejs: { version: 3 },
                            targets: {
                              chrome: '60',
                              firefox: '50'
                            }
                          }
                        ]
                      cacheDirectory: true
                    }
                  }
                ]
              },
              {
                test: /\.(jpg|png|gif)/,
                loader: 'url-loader',
                options: {
                  limit: 8 * 1024,
                  name: '[hash:10].[ext]',
                  outputPath: 'imgs',
                  esModule: false
                }
              },
              {
                test: /\.html$/,
                loader: 'html-loader'
              },
              {
                exclude: /\.(js|css|less|html|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
                  outputPath: 'media'
                }
              }
            ]
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: 'css/built.[contenthash:10].css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true
          }
        }),
        new WorkboxWebpackPlugin.GenerateSW({
          clientsClaim: true,
          skipWaiting: true
        })
      ],
      mode: 'production',
      devtool: 'source-map'
    };
    

    注意点⚠️

    • 多进程打包需要先安装thread-loader,放在某个loader后面就会对某个loader开启多进程打包。可以在options中设置进程个数。
    • 进程启动大概为600ms,进程通信也有开销。所以只有工作消耗时间比较长,才需要多进程打包。

    externals

    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: './src/js/index.js',
      output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html'
        })
      ],
      mode: 'production',
      
      externals: {
        // 拒绝jQuery被打包进来
        jquery: 'jQuery'
      }
    };
    

    注意点⚠️

    • externals配置提供了不从 bundle 中引用依赖的方式。也就是当需要引用一个库,但是又不想让webpack打包(减少打包的时间),并且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用(一般都以import方式引用使用),那就可以通过配置externals。

    dll 动态连接库

    ---------------   webpack.dll.js
    
    /*
      使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
        当你运行 webpack 时,默认查找 webpack.config.js 配置文件
        需求:需要运行 webpack.dll.js 文件
          --> webpack --config webpack.dll.js
    */
    
    const { resolve } = require('path');
    const webpack = require('webpack');
    
    module.exports = {
      entry: {
        // 最终打包生成的[name] --> jquery
        // ['jquery'] --> 要打包的库是jquery
        jquery: ['jquery'],
      },
      output: {
        filename: '[name].js',
        path: resolve(__dirname, 'dll'),
        library: '[name]_[hash]' // 打包的库里面向外暴露出去的内容叫什么名字
      },
      plugins: [
        // 打包生成一个 manifest.json --> 提供和jquery映射
        new webpack.DllPlugin({
          name: '[name]_[hash]', // 映射库的暴露的内容名称
          path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
        })
      ],
      mode: 'production'
    };
    
    ---------------   webpack.config.js
    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    // 引入插件
    const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        filename: 'built.js',
        path: resolve(__dirname, 'build')
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html'
        }),
        // 告诉webpack哪些库不参与打包,同时使用时的名称也得变
        new webpack.DllReferencePlugin({
          manifest: resolve(__dirname, 'dll/manifest.json')
        }),
        // 将某个文件打包输出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
          filepath: resolve(__dirname, 'dll/jquery.js')
        })
      ],
      mode: 'production'
    };
    

    注意点⚠️

    • 创建webpack.dll.js文件,先对某些第三方库进行单独打包。需要设置入口和出口配置,以及调用webpack.DllPlugin打包生成manifest.json文件提供和第三方库的映射。运行指令为webpack --config webpack.dll.js
    • 配置webpack.config.js文件,先找到manifest.json文件,告诉webpack哪些库不参与打包,同时使用时的名称也得变。再运用add-asset-html-webpack-plugin插件,将某个文件打包输出去,并在html中自动引入该资源。

    起源地下载网 » webpack配置(三)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元