A brief study and review of webpack

A brief review of webpack learning

For learning webpack, I personally think it is better to build the framework from scratch manually, then learn webpack, and then use it in the project, because the process of learning is always different from the process of using it. In fact, During the process, various problems will be encountered.

This time I still used webpack4, and I looked at webpack5, but they are almost the same, except that the optimization algorithm and some attributes have to be changed. The author has also mentioned before that webpack5.0 aims to reduce the complexity of configuration and make it easier to get started (I also said this when webpack4)

Just look at my configuration, just read the code comments, coding is too annoying.
Insert image description here
for package.json
Insert image description here

utils

const path = require('path') //node自带路径

exports.resolve = (dir) => path.resolve(__dirname, dir) // 相对位置转换绝对位置

exports.assetsPath = (_path) => path.posix.join("static", _path)

webpack.base.conf.js

const utils = require("./utils")
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')// 处理static下面的静态文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // css单独文件
const WebpackBar = require('webpackbar'); // 美化webpack控制台输出内容
const isDev = process.env.NODE_ENV === 'development'

module.exports = {
    
    
  entry: {
    
     // 入口
    app: ['./src/index.js']
  },
  output: {
    
    // 出口
    path: utils.resolve('../dist'),
    filename: 'static/js/[name]_[hash:6].js',
    publicPath: isDev ? '/' : './', // 打包后资源访问公共路径前缀 
    chunkFilename: 'static/js/[name].[chunkhash:5].chunk.js',
  },
  module: {
    
    // 模块
    rules: [
      {
    
    
        test: /\.(js|jsx|ts|tsx)$/,//一个匹配loaders所处理的文件的拓展名的正则表达式,这里用来匹配js和jsx文件(必须)
        exclude: /node_modules/,//屏蔽不需要处理的文件(文件夹)(可选)
        use: {
    
    
          loader: 'babel-loader',
          options: {
    
      //用babel-loader需要把es6->es5
            presets: [
              '@babel/preset-env',
              ['@babel/preset-react', {
    
     runtime: "automatic" }],  //yarn add @babel/core @babel/preset-react -D
              '@babel/preset-typescript'
            ],
            plugins: [
              '@babel/plugin-proposal-class-properties',
              // '@babel/plugin-syntax-dynamic-import'
            ]
          }
        }
      },
      {
    
    
        test: /\.css$/,
        use: [isDev ? 'style-loader' : {
    
    
          loader: MiniCssExtractPlugin.loader,
          options: {
    
    
            publicPath: '../../'
          }
        }
        , {
    
    
          loader: 'css-loader',
          options: {
    
    
            sourceMap: true,
          }
        },
        {
    
    
          loader: 'postcss-loader',
          options: {
    
    
            postcssOptions: {
    
    
              plugins: [
                require('autoprefixer')
              ]
            }
          }
        },
        ]
      },
      {
    
    
        test: /\.less$/,
        exclude:/\.module\.less$/,
        use: [isDev ? 'style-loader' : {
    
    
          loader: MiniCssExtractPlugin.loader,
          options: {
    
    
            publicPath: '../../' //解决打包图片路径不对
          }
        },
        {
    
    
          loader: 'css-loader',
        },
        {
    
    
          loader: 'postcss-loader',
          options: {
    
    
            postcssOptions: {
    
    
              plugins: [
                require('autoprefixer')
              ]
            }
          }
        },
        {
    
    
          loader: 'less-loader',
        },
        ]
      },
      {
    
    
        test: /\.module\.less$/,
        use: [isDev ? 'style-loader' : {
    
    
          loader: MiniCssExtractPlugin.loader,
          options: {
    
    
            publicPath: '../../'
          }
        },
        {
    
    
          loader: 'css-loader',
          options: {
    
    
            sourceMap: true,
            modules: {
    
    
              localIdentName: isDev ? '[path]_[name]__[local]_[hash:base64:5]' : '[local]_[hash:base64:5]', // 模块化css修改样式名称
            }
          }
        },
        {
    
    
          loader: 'postcss-loader',
          options: {
    
    
            postcssOptions: {
    
    
              plugins: [
                require('autoprefixer')
              ]
            }
          }
        },
        {
    
    
          loader: 'less-loader',
          options: {
    
    
            lessOptions: {
    
    
              module: true
            },
            sourceMap: true,
          }
        },
        {
    
    
          loader: 'style-resources-loader',
          options: {
    
    
            patterns: [utils.resolve('../src/styles/index.less')]// 全局样式文件 可以用全局变量样式和mixins等
          }
        }
        ]
      },
      {
    
    
        test: /\.(png|jpe?g|svg|gif|mp3)$/,
        loader: 'url-loader',  // 这里是loader 写use要报错
        options: {
    
    
          limit: 10000, // url-loader 包含file-loader,这里不用file-loader, 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
          name: 'static/img/[name].[hash:7].[ext]'
        }
      },
      {
    
    
        test: /\.(woff2?|eot|ttf|otf)$/,
        loader: 'url-loader', // 这里是loader 写use要报错
        options: {
    
    
          limit: 10000, // url-loader 包含file-loader,这里不用file-loader, 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
          name: 'static/fonts/[name].[hash:7].[ext]'
        }
      },
    ]
  },
  resolve: {
    
    
    extensions: ['.js', '.json', '.jsx', '.ts', '.tsx'], // 解析扩展。(当我们通过路导入文件,找不到改文件时,会尝试加入这些后缀继续寻找文件)
    alias: {
    
    
      '@': path.join(__dirname, '..', "src"), // 在项目中使用@符号代替src路径,导入文件路径更方便
    }
  },
  plugins: [// 插件
    new CopyWebpackPlugin([
      {
    
    
        from: utils.resolve('../static'),  // 从哪个目录copy
        to: ".", // copy到那个目录
      }
    ]),
    new MiniCssExtractPlugin({
    
    
      filename: utils.assetsPath('css/[name]_[hash:7].css'),
      chunkFilename: utils.assetsPath('css/[id]_[chunkhash:7].css'),
      ignoreOrder: true
    }),
    new WebpackBar()
  ],

}

webpack.dev.conf.js

const webpackMerge = require('webpack-merge') // 合并webpack配置
const baseConfig = require('./webpack.base.conf')
const utils = require('./utils')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 解析html
const portfinder = require('portfinder');//自动查找可用端口
const FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin");//识别某些类的webpack错误,并清除,汇总和优先处理它们
const devWebpackConfig = webpackMerge(baseConfig, {
    
    
  plugins: [ // 插件
    new HtmlWebpackPlugin({
    
    
      filename: utils.resolve('../dist/index.html'), // html模板的生成路径
      template: './public/index.html', // 模板
      favicon: "./public/favicon.ico",
      inject: true, // true:默认值,script标签位于html文件的 body 底部
    }),
  ],
  stats: 'errors-warnings', // 控制台输出内容
  devtool: 'inline-source-map',
  devServer: {
    
    // 开发环境配置
    historyApiFallback: true, // 当找不到路径的时候,默认加载index.html文件
    hot: true,
    contentBase: false, // 告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要
    // compress: true, //一切服务器都用gzip
    inline: true,
    port: 5500, // 端口
    publicPath: '/', // 前缀
    open: true, // true,打开默认浏览器
    host: "localhost", //设置本地url
    overlay: {
    
     // 错误全屏显示
      errors: true,
      warnings: false
    },
    proxy: {
    
    
      // // 接口请求代理
      // "/api": {
    
    
      //   secure: false,
      //   target: "http://127.0.0.1:8082"
      // }
    },
  }
})
module.exports = new Promise((resolve, reject) => {
    
    
  portfinder.basePort = devWebpackConfig.devServer.port;
  portfinder.getPort((err, port) => {
    
    
    if (err) {
    
    
      reject(err)
    } else {
    
    
      process.env.PORT = port
      devWebpackConfig.devServer.port = port
      devWebpackConfig.plugins.push(
        new FriendlyErrorsWebpackPlugin({
    
    
          compilationSuccessInfo: {
    
    
            messages: [
              `Your application is running here: http://${
      
      devWebpackConfig.devServer.host}:${
      
      port}`
            ],
            notes: []
          },
          clearConsole: true
        })
      )

      resolve(devWebpackConfig)
    }
  })
})

webpack.prod.conf.js

const HtmlWebpackPlugin = require("html-webpack-plugin") // 解析html文件
const utils = require("./utils") // 导入公共方法
const webpackMerge = require('webpack-merge') // 合并webpack配置
const baseConfig = require('./webpack.base.conf')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; //打包完成,可视化查看每个文件大小
const {
    
     CleanWebpackPlugin } = require('clean-webpack-plugin'); // 每次打包清理文件
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩css
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); // 压缩js
const CompressionWebpackPlugin = require('compression-webpack-plugin')//压缩为gizp

module.exports = webpackMerge(baseConfig, {
    
    
  plugins: [ // 插件
    new HtmlWebpackPlugin({
    
    
      filename: utils.resolve('../dist/index.html'), // html模板生成路径
      template: './public/index.html', // 模板
      favicon: "./public/favicon.ico",
      inject: true, // true 默认值 script标签位于body底部
      hash: true, // 打包资源插入html加上hash
      // html文件压缩
      minify: {
    
    
        removeComments: true, // 去除注释
        collapseWhitespace: true, // 压缩空间
        removeAttributeQuotes: true // 去除属性 标签的 引号  例如 <p id="test" /> 输出 <p id=test/>
      }
    }),
    new CompressionWebpackPlugin({
    
    
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      deleteOriginalAssets: true,
      test: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i,
      deleteOriginalAssets: true,
      threshold: 10240,
      minRatio: 0.8
     }),
    new BundleAnalyzerPlugin(),
    new CleanWebpackPlugin(),
  ],

  optimization: {
    
     // 优化
    splitChunks: {
    
    
      chunks: 'async',//表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为 async
      minSize: 30000,//表示在压缩前的最小模块大小
      maxSize: 0,
      minChunks: 1,//表示被引用次数
      maxAsyncRequests: 5,//按需加载时候最大的并行请求数
      maxInitialRequests: 3,// 一个入口最大的并行请求数
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
    
    //缓存组。缓存组的属性除上面所有属性外
        vendors: {
    
    
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        commons: {
    
    
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
        default: {
    
    
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    },
    minimizer: [  // 压缩css
      new UglifyJsPlugin({
    
    
        parallel: true,  //使用多进程并行运行来提高构建速度
        cache: true, // Boolean/String,字符串即是缓存文件存放的路径
        uglifyOptions: {
    
    
          warnings: false,
          output: {
    
    
            comments: false,   // 使输出的代码尽可能紧凑
            beautify: false  // 输出删掉所有注释
          },
          compress: {
    
    
            drop_console: true, // 过滤console,即使写了console,线上也不显示
            drop_debugger: true,
            // warnings:false// UglifyJs版本跟这个没对应上
          }
        }
      }),
      new OptimizeCSSAssetsPlugin({
    
    
        assetNameRegExp: /\.(less)|(css)$/g,
        cssProcessor: require('cssnano'), // 用这个压缩过后更小
        cssProcessorOptions: {
    
    
          safe: true,
          discardComments: {
    
     removeAll: true }, // 移除注释
          normalizeUnicode: false // 建议false,否则在使用unicode-range的时候会产生乱码
        },
        canPrint: true
      }),
    ]
  },
})

Then this is a demo I practiced.
Insert image description here
Through my own practice, I can speak much better than others. No matter how well others speak, others will get it. After all, stupid people are diligent in making up for their mistakes.

Reference: Nuggets

demo address: github

Guess you like

Origin blog.csdn.net/nihaio25/article/details/129689695