浅谈 webpack@5 基本使用

321 阅读3分钟
  1. 概念 webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点(entry)构建一个 依赖图,然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
  2. 安装
    //全局安装
    npm install webpack wabpack-cli --global
    //局部安装
    npm install webpack webpack-cli --save-dev
    
  3. webpack 中 一些常用的 loader 和 plugin
    • loader
      1. style-loader css-loader sass-loader less-loade stylus-loader 用来处理css 和 一些css 的预处理器;
      2. babel-loader 将ES6或者更高版本的代码转为ESS。使用bable-loader那么以下这些插件也必须得安装,配套使用@babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/runtime
      3. ts-loader 处理ts语法 需安装typescript这个插件,如果使用了ts,那么上边使用的babel有些需要修改;
      4. 在webpack@4 的版本中,还需要file-loader url-loader raw-loader 在webpack@5中,我们使用asset模块来替代。(asset/resource代替file-loaderasset/inline代替url-loaderasset/source代替raw-loader)。
    • plugin 1.html-webpack-plugin这个插件在打包后为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle; 2.MiniCssExtractPlugin CssMinimizerPlugin 这两个个插件用来打包后压缩css文件; 3.terserPlugin 压缩js文件; 4.json5 这个可能不算plugin吧,传统意义上的json文件是不允许写注释且key必须得用引号包裹,而json不需要。
  4. 项目根目录下创建webpack.config.js(webpack 配置文件)
    //webpack.config.js
    const path = require('path'); //导入path 模块
    module.exports = {
      entry: './src/index.js', //入口文件
      output: { //打包后文件的目录位置
        path: path.resolve(__dirname, './dist'),
        filename: 'index.js'
      } 
    }
    
  5. 在webpack中我们可以使用动态导报,就是按需加载包
    // main.js 这样我们能实现在用户不点击按钮的时候是不会加载math.js 这个模块,点击再加载。注:下边的 '/**/' 不是注释 webpackPrefetch: true 预加载
    let btn = document.createElement('button');
    btn.textContent = "点击求和"
    btn.addEventListener('click', ()=> {
      import(/* wepbackChunkName: xxx, webpackPrefetch: true */'./math').then(({add}) => {
        console.log(add(5,5)) //10
      })
    })
    document.body.appendChild(btn)
    
    //math.js
    export function(x, y) {
      return x + y
    }
    
  6. 以下是一份常用的webpack.config.js 用的loader 和 plugin
    const path = require('path'); //导入path 模块
    // npm i html-webpack-plugin -D
    const HtmlWebpackPlugin = require('html-webpack-plugin'); //导入 html-webpack-plugin 插件
    /**
     * npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
     * 这两个 plugin 的作用是将css文件打包到指定文件并且压缩css文件
     * MiniCssExtractPlugin 将css文件打入指定文件下
     * CssMinimizerPlugin 压缩css文件
     *  */ 
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    //生产环境下压缩js代码 
    const terserPlugin = require('terser-webpack-plugin');
    // npm i json5 -D
    const json5 = require('json5');
    module.exports = {
      //入口文件
      entry: {
        main: './src/main.js'
      }, 
      //打包后文件的目录位置
      output: { 
        path: path.resolve(__dirname, 'dist'),
        filename: 'script/[name].[contenthash].js',
        //打包前清理 dist 目录
        clean: true,
        //资源模块文件名 定义文件路径和文件名称 不推荐写在这里, 如果在 rules 中定义了 generator ,那么 generator 优先执行
        assetModuleFilename: 'images/[contenthash][ext]'
      },
      //mode 可选值为 'development', 'production', 'none', 不设置会有警告提示
      mode: 'production',
      devtool: 'inline-source-map',
      //配置插件
      plugins:[
        new HtmlWebpackPlugin({ template: './src/index.html' }),
        new MiniCssExtractPlugin({
          filename: './css/[contenthash].css'
        })
      ],
      optimization: {
        //打包分离公用模块,并且缓存
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendors',
              chunks: 'all'
            }
          }
        },
        minimizer: [
          new CssMinimizerPlugin(),
          new terserPlugin()
        ],
        /**
         * minimize: true
         * 如果 minimize 值为 false 的时候, mode 必须 设为 'production', css 代码才会压缩
         * 如果 minimize 值为 true 的时候, mode 设为 'development', css 代码也会压缩
         */
        minimize: true
      },
      // webpack-dev-server (npx webpack-dev-server)
      devServer: {
        static: {
          directory: path.resolve(__dirname, 'src')
        },
        port: 3693,
      },
      //资源模块
      module: {
        rules: [
          {
            test: /\.(png|jpg)$/,
            /**
             * 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现
             * ex: http://192.168.1.98:3693/./images/1d4a4ee6a0400c74b7b9.jpg
             */
    
            type: 'asset/resource',
            generator: {
              filename: './images/[contenthash][ext]'
            }
          },
          {
            test: /\.webp$/,
            /**
             * 导出一个资源的 data URI。之前通过使用 url-loader 实现, 不需要配置 generator
             * ex: data:image/webp;base64,UklGRrpDAABXRUJQVlA4IK5DAACQnAGdASr0ARACPpFCnUqlo6KuJfPK....
             */
            type: 'asset/inline'
          },
          {
            test: /\.txt$/,
            /**
             * 导出资源的源代码。之前通过使用 raw-loader 实现, 不需要配置 generator
             * ex: 1233322323
             */
            type: 'asset/source'
          },
          {
            test: /\.gif$/,
            /**
             * 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader 实现
             */
            type: 'asset',
            parser: {
              dataUrlCondition: {
                //默认不设置的话,取值范围为8kb
                //当文件超过4M的时候就使用 [sset/resource] 否则 [asset/inline]
                maxSize: 4 * 1024 * 1024
              }
            }
          },
          {
            test: /\.(scss|sass|css)$/,
            /**
             * 在 webpack 中引入css| scss等,需要使用 以下loader 
             * npm install css-loader style-loader sass-loader sass -D (tips: 如果使用less 就安装 less-loader less)
             * use 的使用顺序一定不能写错,切记切记,顺序不能错
             * 使用 style-loader 会把我们的样式放到 <head><style>....</style></head>
             * use: ['style-loader', 'css-loader', 'sass-loader']
             * 如果我们希望 link 引入样式文件,就需要 MiniCssExtractPlugin 这个插件
             * use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
             */
            use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
          },
          {
            test: /\.(woff|woff2|eot|ttf|otf)$/,
            /**
             * 加载icon字体文件
             */
            type: 'asset/resource'
          },
          {
            test: /\.json5$/,
            /**
             * json5 与 json 类似,完善了一些json不支持的格式
             * 在json中是不能写注释的,并且 key 必须用引号包住,
             * json5中不需要,很强大,哈哈哈哈
             */
            type: 'json',
            parser: {
              parse: json5.parse
            }
          },
          {
            /**
             * 使用 babel-loader 转换 es6 js 代码
             * 安装loader npm install babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/runtime -D
             * 
             */
            test: /\.m?js$/,
            exclude: /(node_modules|bower_components)/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env'],
                plugins: ['@babel/plugin-transform-runtime']
              }
            }
          }
        ]
      }
    }