webpack配置整理


最近在学习webpack,整理一下代码

主文件webpack.config.js

// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const miniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
// Happypack任务分解为多个子进程,完成后并入主线程(适合大型项目)
const HappyPack = require('happypack');
// 根据cpu数量创建线程池
const happyThreadPool = HappyPack.ThreadPool({size:OscillatorNode.cpus().length});
/*
PWA:渐进式网络开发应用程序(离线可访问)
workbox --> workbox-webpack-plugin
 */
const workBoxWebpackPlugin = require('workbox-webpack-plugin');
// 以前使用的是Ulgify,现在webpack内置terser plugin进行文件压缩优化
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
/*
tree shaking:去除无用代码
前提:1.必须使用es6模块化 2.开启production模块
作用:减少代码体积
"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把除了js文件之外的文件也去除掉可以通过"sideEffects": ["*.css"]不进行tree shaking
 */
const commonCssLoader = [
  // use数组中loader顺序:从后到前的顺序,依次执行
  // 创建style标签,将js中的样式资源插入进行,添加到head中生效
  // 'style-loader',
  // 取代style-loader 作用:提取js中的css成单独文件
  miniCssExtractPlugin.loader,
  // 将css文件变成commonjs模块加载到js中,里面内容是样式字符串
  'css-loader',
  /*
   css 兼容性处理:postcss --> postcss-loader postcss-preset-env
   */
  // 使用loader的默认配置
  // postcss-loader 修改loader的配置
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [
        // postcss的插件
        require('postcss-preset-env')()
      ]
    }
  }];
process.env.NODE_ENV = 'development';
module.exports = {
  // import导入的没有加后缀的文件,自动加上后缀
  resolve: {
    extensions: ['.js']
  },
  // webpack配置
  // 入口起点
  entry: ['./index.js', './demo.html'],
  output: {
    // 输出文件名
    filename: 'js/built.js',
    // 输出路径
    path: resolve(__dirname, 'build')
  },
// loader的配置
  module: {
    // 不打包的文件
    noParse: /node_modules/(echarts)/,
    // 详细loader配置
    rules: [
      // 1.js兼容性处理:babel-loader @babel/preset-env @babel/core
      // 问题:babel只能转换一些基本语法 例如:Promise就不能转换
      // 2. 全部js兼容性处理 --> @babel/polyfill
      // 解决了所有的兼容性问题,但是打包后的文件体积过大
      // 3.需要做兼容性处理的才进行改良:按需加载 --> core.js
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: [
          // 开启多进程打包
          // 进程启动大概为600ms,进程通信也有开销
          // 只有工作消耗时间比较长,才需要多进程打包
          'thread-loader',
          {
            loader: 'babel-loader',
            options: {
              // 预设:指示babel做怎样的兼容性处理
              presets: [
                ['@babel/preset-env',
                  {
                    // 按需加载
                    useBuiltIns: 'usage',
                    // // 指定core-js版本
                    corejs: {
                      version: 3
                    },
                    // 指定兼容性做到哪个版本的浏览器
                    targets: {
                      chrome: '60',
                      firefox: '60',
                      ie: '9',
                      safari: '10',
                      edge: '17'
                    }
                  }]
              ],
              // 开启babel缓存
              // 第二次构建,会读取之前的缓存
              cacheDirectory: true,
              /*
              文件资源缓存
              hash:每次webpack构建时会生成一个唯一的hash值。
              问题:因为js和css同时使用一个hash值
              如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
              chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
              因为css是在js中被引入的,所以同属于一个chunk
              contenthash:根据文件的内容生成hash值,不同文件hash值一定不一样 --> 让代码上线运行缓存更好使用
               */
            }
          }
        ]
      },
      // 语法检查:eslint-loader eslint
      // 只检查自己写的源代码,不检查第三方库的代码
      // 设置检查规则: package.json中eslintConfig中设置~
      // 推荐airbnb规则 --> eslint-config-airbnb-base eslint eslint-plugin-import
      {
        test: /.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        enforce: 'pre',
        options: {
          // 自动修复语法
          fix: true
        }
      },
      {
        // 以下loader只会执行一个
        // 如果有两个loader同时处理一种类型文件,则会出错
        oneOf: [
          {
            test: /.css$/,
            use: [...commonCssLoader]
          },
          {
            // 匹配哪些文件
            test: /.less$/,
            // 使用哪些loader进行处理
            use: [
              ...commonCssLoader,
              'less-loader'
            ]
          },
          {
            test: /.(jpg|png|gif)$/,
            // 需要下载两个loader,下载url-loader以及它依赖的file-loader
            loader: 'url-loader',
            options: {
              // 图片小于8kb,就会被base64处理
              // 优点:减少请求数量(减轻服务器压力)
              // 缺点:图片体积会更大(文件请求速度更慢)
              limit: 8 * 1024,
              esModule: false,
              outputPath: 'images',
              name: '[hash:10].[ext]'
            }
          },
          {
            test: /.html$/,
            // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
            loader: 'html-loader'
          },
          // 打包其他资源(除了html/js/css资源以外的资源)
          {
            exclude: /.(js|css|html|less|jpg|png|gif)$/,
            loader: 'file-loader',
            options: {
              outputPath: 'media',
              name: '[hash:10].[ext]'
            }
          }
        ]
      }
    ]
  },
  // externals: {
  //   // 忽略库名 -- npm包名,设置之后的库不参与打包
  //   jquery: 'jQuery'
  // },
  // plugins的配置
  plugins: [
    // 详细plugins的配置
    // html-webpack-plugin
    // 功能:默认会创建一个空的html,自动引入打包输出的所有资源(JS/CSS)
    // 需求:需要有结构的HTML文件
    new htmlWebpackPlugin({
      template: './demo.html',
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除注释
        removeComments: true
      }
    }),
    new CleanWebpackPlugin(),
    new miniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    // 压缩CSS
    new optimizeCssAssetsWebpackPlugin(),
    new workBoxWebpackPlugin.GenerateSW({
      /*
      1.帮助serviceworker快速启动
      2.删除旧的serviceworker
      生成一个serviceworker配置
       */
       clientsClaim:true,
      skipWaiting: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    // 告诉webpack那些库不参与打包,同时使用时的名称也得变~
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')
    }),
    new BundleAnalyzerPlugin(),
    new HappyPack({
      id: 'babel',
      threads: happyThreadPool,
      // happypack有很多不支持的loader,请查看官方进行使用
      loaders: ['babel-loader']
    })
    // 将某个文件打包输出去,并在html中自动引入该资源
    // new addAssetHtmlWebpackPlugin({
    //   filepath: resolve(__dirname, 'dll/jquery.js')
    // })
  ],
  // 模式
  mode: 'production', // 开发模式
  /*
  可以将node_modules中代码单独的打包一个chunk最终输出
  自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独一个chunk
   */
  optimization: {
    splitChunks: {
      chunks: 'all'
    },
    minimizer: [
       new TerserPlugin({
         // 加快构建速度
         cache: true,
         // 开启多线程
         // parallel: true,
         terserOptions: {
           // 打包时将无用代码去除
           compress: {
             unused: true,
             drop_debugger: true,
             drop_console: true,
             dead_code: true
           }
         }
       })
    ]
  },
  // 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器...)
  // 特点:只会在内存中编译打包,不会有任何输出
  // 启动devServer指令为:npx webpack-dev-server
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    /*
    HMR:hot module replacement 热模块替换/模块热替换
    作用:一个模块发生变化,只会重新打包一个模块(而不是打包所有模块)
    极大提升构建速度

    样式文件:可以使用HMR功能,但是需要使用style-loader,style-loader内部实现了HMR
    js文件:默认不能使用HMR功能 -> 需要修改js代码,添加支持HMR功能的代码
    注意:HMR功能对js的处理,只能处理非入口js文件的其他文件
    html文件:默认不能使用HMR功能,同时会导致问题,html文件不能热更新,解决:修改entry入口,将html文件引入
     */
    hot: true,
    hotOnly: true,
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000
  },
  devtool: 'source-map'
};
/*
source-map:一种 提供源代码到构建后代码映射 技术(如果构建后代码出错了,通过映射可以追踪源代码错误)
[inline-[hidden-[eval-][nosources-][cheap-[module-]]source-map

inline-source-map:内联(只生成一个sourceMap)
hidden-source-map:外部
eval-source-map:内联(每个文件生成一个sourceMap)
nosources-source-map:外部
cheap-source-map:外部
cheap-module-source-map: 外部
 */
/* package.json添加配置
"browerslist": {
    "development": [
      "last 1 chrome version", // 最近的一个版本
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production": [
      ">0.2%", // 全球有0.2%的用户使用的浏览器(也就是兼容的浏览器很老)
      "not dead", // 
      "not op_mini all" // 不兼容op_mini
    ]
  },
  "eslintConfig": {
    "extends": "airbnb-base", // 遵从airbnb代码风格
    "env": {
      "browser": true, // 浏览器环境
      "es6": true
    }
  },
  "sideEffects": false // 启动tree shaking
*/

dll文件

/*
 使用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'
};
原文地址:https://www.cnblogs.com/smallZoro/p/12722174.html