webpack基础配置

webpack基础配置-很全

    • 开发环境配置
    • 生产环境配置
    • 总结
        • 1. 提升开发体验
        • 2. 提升 webpack 打包构建速度
        • 3. 减少代码体积
        • 4. 优化代码运行性能

本文是自学webpack的全过程,能够结合Vue、React框架直接使用,并且总结了关于webpack的代码优化内容,希望对您有帮助。
附上个人git仓库地址:https://gitee.com/zhaosir1/webpack_code.git

开发环境配置

  1. 在根目录创建config文件夹,里面分别创建webpack.dev.js(开发环境)和webpack.prod.js(生产环境)配置文件。

  2. 文件目录结构(仅用于测试webpack的配置)。
    webpack基础配置_第1张图片

  3. webpack.dev.js文件配置。

const ESLintPlugin = require('eslint-webpack-plugin'); //语法检查插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); //处理html文件的插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //解析css的插件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");//压缩css的插件
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");//压缩图片的插件
const path = require('path') //处理路径
const os = require("os"); //获取cpu的内核数量,
const TerserPlugin = require("terser-webpack-plugin");//压缩js的插件
// 核数
const threads = os.cpus().length;
// 获取处理样式的loder (由于很多css的loader用法很相似,因此提取出公共部分代码)
function getStyleLoder(pre) {
  return [ //执行顺序从下到上
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    pre //如需使用其他loader可以通过传参的方式引入
  ].filter(Boolean) //过滤掉undefined
}
module.exports = {
  // 打包入口文件
  entry: './src/main.js',
  // 文件输出配置
  output: {
    // 输出路径
    // path: path.resolve(__dirname, 'dist'),
    // 开发环境没有输出-可以配置 undefined
    path: undefined,
    // 输出的文件名
    filename: 'static/js/[name].js',
    // 自动清空上传打包的资源
    // 开发环境没有输出打包资源所以不用配置
    // clean:true
    // 打包输出其他文件命名
    chunkFilename:'static/js/[name].chunk.js',
    // 图片 字体等通过type:asset处理资源命名方式
    assetModuleFilename:'static/image/[hash:10][ext][query]'
  },
  // 加载器
  module: {
    rules: [ //loder配置
      {
        oneOf: [{ //处理css文件
            test: /\.css$/,
            use: getStyleLoder()
          },
          {//处理less文件
            test: /\.less$/,
            use: getStyleLoder("less-loader")
          },
          {//处理sass scss文件
            test: /\.s[ac]ss$/,
            use: getStyleLoder("sass-loader")
          },
          {//处理styl文件
            test: /\.styl$/,
            use: getStyleLoder("stylus-loader")
          },
          {//处理图片资源
            test: /\.(png|jpe?g|gif|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024 //小于10kb转base64格式 减少请求次数
              }
            },
            // generator: { //图片输出位置--开发环境无需配置
            //   filename: 'static/image/[hash:10][ext][query]'
            // }
          },
          { //处理字体图标音视频等其他资源文件
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
            type: "asset/resource",
            // generator: { //输出位置--开发环境无需配置
            //   filename: 'static/media/[hash:10][ext][query]'
            // }
          },
          { //处理js文件  解决低版本浏览器对js的兼容问题
            test: /\.m?js$/,
            // exclude: /(node_modules)/, //排除node_modules文件夹
            include: path.resolve(__dirname, '../src'), //只处理src文件夹下面的js文件(exclude|include 两者选择其一即可)
            use: [{
              loader: 'thread-loader', //开启多进程
              options: {
                works: threads //进程数量
              }
            },
            {
              loader: 'babel-loader',
              options: {
                // presets: ['@babel/preset-env']  //babel预设也可抽离出单独文件进行配置(babel.config.js)文件
                cacheDirectory: true, //开启babel缓存
                cacheCompression: false, //关闭缓存文件压缩
                plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
              },
            }
          ]
          }
        ]
      }

    ]
  },
  // 插件
  plugins: [
    new ESLintPlugin({ //代码检查
      context: path.resolve(__dirname, '../src'),
      exclude: 'node_modules', //默认值,排除node_modules文件夹
      cache:true, //开启缓存
      cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache'),
      threads //开启多进程
    }),
    new HtmlWebpackPlugin({ //处理html文件 自动引入资源
      template: path.resolve(__dirname, '../public/index.html')
    }),
    new MiniCssExtractPlugin(),//解析css的插件
    
    // new CssMinimizerPlugin(),
    // new TerserPlugin({
    //   parallel:threads//开启多进程
    // })
  ],
  //webpack5之后 官方建议把处理文件压缩的插件放在optimization配置项里面
  optimization: { //压缩的操作也可以放着
    minimizer: [
      // 压缩css
      new CssMinimizerPlugin(),
      // 压缩js
      new TerserPlugin({
        parallel: threads //开启多进程
      }),
      // 压缩图片-按照官方写即可
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
    // 代码分割配置
    splitChunks: {
      chunks: 'all'
    }
  },
  // 开发服务器: 内存中运行
  devServer: {
    host: "localhost", // 启动服务器域名
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
    hot: true, //开启HDM(热更新)
  },
  // 模式
  mode: 'development',
  // 用于配置soutceMap(源文件映射),
  // 当代码报错时,能够清晰的显示出是具体对于源文件的哪一行报错
  devtool: "cheap-module-source-map",
}
  1. 由于使用到了eslint语法检查,所以还要在根目录创建.eslintignore文件(忽略不用检查的文件夹)和.eslintrc.js文件(语法检查配置项)
  2. .eslinignore文件,直接把需要忽略的文件夹名称放进去即可,和git的.ignore文件用法一样
  3. .eslintrc.js文件配置内容:
module.exports = {
  // 继承 Eslint 规则
  // 如需使用vue或者react 此处直接继承官方的写法即可 (vue-app|react-app)
  extends: ["eslint:recommended"],
  env: {
    node: true, // 启用node中全局变量
    browser: true, // 启用浏览器中全局变量
  },
  parserOptions: {
    ecmaVersion: 6, //es6
    sourceType: "module", //es module
  },
  // 如需重构,在下面配置即可覆盖
  rules: {
    "no-var": 2, // 不能使用 var 定义变量
  },
  plugins:['import'] //允许使用import关键词引入文件
};
  1. babel智能预设配置,在根目录创建babel.config.js文件:
module.exports = {
  presets: [
    //智能预设,能够编译ES6语法
    // 如果使用vue和react可以直接使用方法预设 presets:['react-app'] | presets:['vue-app']
    ['@babel/preset-env', {
      //usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。
      useBuiltIns: 'usage',
      corejs: 3 //确定corejs的版本
    }],
  ]
}
  1. 由于配置了浏览器的兼容,为了摒弃一些不常用的浏览器,要在package.json里面添加配置:
"browserslist": [
    "last 2 version",
    "> 1%",
    "not dead"
  ],

“last 2 version":兼容到浏览器最新的两个版本
“> 1%” :兼容99%的浏览器
“not dead”:摒弃已经废弃的浏览器

到此为止开发环境的webpack配置已经完成可通过命令:webpack serve --config ./config/webpack.dev.js进行开发环境的打包操作。

生产环境配置

  1. 在config文件夹创建webpack.prod.js配置文件:
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
const os = require("os");
const WorkboxPlugin = require('workbox-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
// 核数
const threads = os.cpus().length;
const path = require('path')
// 获取处理样式的loder
function getStyleLoder(pre) {
  return [ //执行顺序从下到上
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    pre
  ].filter(Boolean)
}
module.exports = {
  // 入口
  entry: './src/main.js',
  // 输出
  output: {
    // 输出路径
    path: path.resolve(__dirname, '../dist'),
    // 入口文件打包输出文件名
    filename: 'static/js/[name].js',
    // 自动清空上传打包的资源
    clean: true,
    // 打包输出其他文件命名
    chunkFilename:'static/js/[name].chunk.js',
    // 图片 字体等通过type:asset处理资源命名方式
    assetModuleFilename:'static/image/[hash:10][ext][query]'
  },
  // 加载器
  module: {
    rules: [ //loder配置
      {
        oneOf: [{
            test: /\.css$/,
            use: getStyleLoder()
          },
          {
            test: /\.less$/,
            use: getStyleLoder("less-loader")
          },
          {
            test: /\.s[ac]ss$/,
            use: getStyleLoder("sass-loader")
          },
          {
            test: /\.styl$/,
            use: getStyleLoder("stylus-loader")
          },
          {
            test: /\.(png|jpe?g|gif|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024 //小于10kb转base64 减少请求次数
              }
            },
            // generator: { //图片输出位置
            //   filename: 'static/image/[hash:10][ext][query]'
            // }
          },
          { //字体图标音视频等其他资源文件
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
            type: "asset/resource",
            // generator: { //输出位置
            //   filename: 'static/media/[hash:10][ext][query]'
            // }
          },
          { //处理js文件  兼容 todo
            test: /\.m?js$/,
            // exclude: /(node_modules)/, //排除node_modules
            include: path.resolve(__dirname, '../src'), //只处理src文件夹下面的js文件
            use: [{
                loader: 'thread-loader', //开启多进程
                options: {
                  works: threads //进程数量
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  //   presets: ['@babel/preset-env']
                  cacheDirectory: true, //开启babel缓存
                  cacheCompression: false, //关闭缓存文件压缩
                  plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
                },
              }
            ]
          }
        ]
      }


    ]
  },
  // 插件
  plugins: [
    new ESLintPlugin({ //代码检查
      context: path.resolve(__dirname, '../src'),
      exclude: 'node_modules', //默认值,排除node_modules文件夹
      cache: true, //开启缓存
      cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'),
      threads //开启多进程
    }),
    new HtmlWebpackPlugin({ //处理html文件 自动引入资源
      template: path.resolve(__dirname, '../public/index.html')
    }),
    new MiniCssExtractPlugin({ //提取css成单独的文件
      filename: 'static/css/[name].[contenthash:10].css',
      chunkFilename: 'static/css/[name].chunk.[contenthash:10].css',
    }),
    // new CssMinimizerPlugin(),
    // new TerserPlugin({
    //   parallel:threads//开启多进程
    // })
    // js按需加载  缓存
    new PreloadWebpackPlugin({
      rel:'preload',
      as:'script'
      // rel:'prefetch'
    }),
    new WorkboxPlugin.GenerateSW({
      // 这些选项帮助快速启用 ServiceWorkers
      // 不允许遗留任何“旧的” ServiceWorkers
      clientsClaim: true,
      skipWaiting: true,
    }),
  ],
  optimization: { //压缩的操作也可以放着
    minimizer: [
      // 压缩css
      new CssMinimizerPlugin(),
      // 压缩js
      new TerserPlugin({
        parallel: threads //开启多进程
      }),
      // 压缩图片
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", {
                interlaced: true
              }],
              ["jpegtran", {
                progressive: true
              }],
              ["optipng", {
                optimizationLevel: 5
              }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      })
    ],
    // 代码分割配置
    splitChunks: {
      chunks: 'all'
    },
    runtimeChunk: {
      name:(entrypoint)=>`runtuime~${entrypoint.name}.js`,
    }
  },
  // 开发服务器: 内存中运行
  // 生产模式不需要
  // devServer: {
  //   host: "localhost", // 启动服务器域名
  //   port: "3000", // 启动服务器端口号
  //   open: true, // 是否自动打开浏览器
  // },
  // 模式
  mode: 'production',
  devtool: "source-map",
}
  1. 生产环境配置和开发环境配置大部分内容都是一样的。运行打包命令:webpack --config ./config/webpack.prod.js即可进行生产环境的打包操作
  2. 为了更方便打包,可在package.json文件进行命令的配置:
 "scripts": {
    "start": "npm run dev",
    "dev": "webpack serve --config ./config/webpack.dev.js",
    "build": "webpack --config ./config/webpack.prod.js"
  },

即开发环境打包命令:npm start 或者 yarn start
生产环境打包命令:npm run build 或者 yarn run build

总结

1. 提升开发体验

  1. 使用 Source Map 让开发或上线时代码报错能有更加准确的错误提示。

2. 提升 webpack 打包构建速度

  1. 使用 HotModuleReplacement 让开发时只重新编译打包更新变化了的代码,不变的代码使用缓存,从而使更新速度更快。
  2. 使用 OneOf 让资源文件一旦被某个 loader 处理了,就不会继续遍历了,打包速度更快。
  3. 使用 Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。
  4. 使用 Cache 对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。
  5. 使用 Thead 多进程处理 eslint 和 babel 任务,速度更快。(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)

3. 减少代码体积

  1. 使用 Tree Shaking 剔除了没有使用的多余代码,让代码体积更小。
  2. 使用 @babel/plugin-transform-runtime 插件对 babel 进行处理,让辅助代码从中引入,而不是每个文件都生成辅助代码,从而体积更小。
  3. 使用 Image Minimizer 对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)

4. 优化代码运行性能

  1. 使用 Code Split 对代码进行分割成多个 js 文件,从而使单个文件体积更小,并行加载 js 速度更快。2. 并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。
  2. 使用 Preload / Prefetch 对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。
  3. 使用 Network Cache 能对输出资源文件进行更好的命名,将来好做缓存,从而用户体验更好。
  4. 使用 Core-js 对 js 进行兼容性处理,让我们代码能运行在低版本浏览器。
  5. 使用 PWA 能让代码离线也能访问,从而提升用户体验。

特别感谢:尚硅谷
本人webpack初学者,如有大神有高见随时求打扰,如有不解也可在评论区相互探讨相互进步。
给个小赞谢谢

你可能感兴趣的:(webpack,webpack,javascript,前端,vue.js,react)