小言_互联网的博客

一篇弄懂webpack静态资源打包器

343人阅读  评论(0)

认识

webpack是优秀的前端构建工具,静态资源打包器,可以根据模块依赖关系进行静态资源分析,快速打包生成相对应浏览器可以直接识别的静态资源!

环境

1)node环境

2)vs code编辑器

规约

1)入口文件:

开始打包第一个文件称为入口文件,通常经过在入口文件中引入其他资源,形成资源关系树状图。webpack根据依赖关系进行一次处理。

2)chunk代码块:

管理webpack内部的打包进程,chunk可以分为“入口”和“子代码块”,入口文件就是一个chunk,默认的webpack打包配置是一个入口文件是一个chunk,打包生成一个bundle。但是如果出现代码分割的情况下,有多个chunk打包生成一个bundle。

3)bundle:

通过处理入口文件中的关系依赖,最后打包输出成为浏览器可以直接识别的静态资源文件就是bundle。

安装webpack环境

1)项目根目录控制台执行指令:npm init,生成package.json文件,npm是新版本node自带的包管理工具,而package.json相当于清单,记录依赖库和项目信息的文件。

2)全局安装webpack指令: npm i webpack webpack-cli -g ,全局安装是指系统环境中,任何项目文件夹下都可以使用指令,其中mac电脑首次执行应该是需要管理员权限,sudo npm i webpack webpack-cli -g 如果网速太慢则建议切换为淘宝镜像源。

3)本地安装webpcak指令: sudo npm i webpack webpack-cli -D,下载的模块是注入于本项目下的./node_nodules文件夹中,不会影响其他项目,起到独立的作用!

概念核心:

Entry

入口文件指示,配置wepack以哪个入口文件进行打包分析等参数。

entry: "./src/main.js",

Output

出口文件指示,配置webpack打包后的资源bundle输出资源的路径及参数。

output: {
   
  filename: "static/js/[name].js",
  path: resolve(__dirname, "build"),
},

Loader

webpack本身仅能识别js、json代码,而Loader的作用就是将CSS、img、字体资源翻译成为webpack可以识别的资源,可以识别后才可以进行打包处理!loader通过npm安装依赖之后就可以配置,不用需要引入。

1)Es语法检查配置:
// eslint语法检查
{
   
  /**
   * js语法所需loader安装指令:npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
   * eslint的js语法检查是依托于airbnb规则进行检查,根据package.json下的eslintConfig的配置进行检测语法。
   * airbnb默认是不能认识window等对象,可通过eslintConfig下的env属性进行屏蔽检查,可通过eslint-disable-next-line注释取消下一行的语法检查。
   */
  test: /\.js$/, // 通过正则匹配后缀名为.js的文件
  enforce: "pre", // 设置loader的执行顺序,pre(优先)| post(延后)。
  exclude: /node_modules/, // 排除node_modules目录下js文件的语法检查
  loader: "eslint-loader", // 指定eslint-loader执行处理js文件进行语法检查
  options: {
   
    fix: true, // 配置参、空格、缩进不规范的语法自动进行修复。
  },
},
2)处理CSS文件并兼容:
{
   
	// 处理css文件的规则所需loader安装指令:npm i style-loader -D 和 npm i css-loader -D
	test: /\.css$/,
	// 处理文件时使用到多个lorder时,执行顺序为从下到上。
	use: [
	  // "style-loader", // 处理创建style标签,将js中处理的资源添加到style标签中,再添加到页面head中生效。
	  {
   
	    loader: MiniCssExtractPlugin.loader, // 因为css引入js文件中,会造成js代码文件过大,所以通过MiniCssExtractPlugin构造函数自带loader取代style-loader,作用为将css抽离成为单个文件通过link标签引入。
	    options: {
   
	      publicPath: "../../", // 资源引入html文件时的路径前缀,因为css文件以及被单独抽离至特定目录下,正确修改才能匹配到css中引用的静态资源。
	    },
	  },
	  // 翻译css使webpack能够识别css样式语法
	  "css-loader",
	  {
   
	    loader: "postcss-loader", // 使用postcss进行浏览器兼容,使用的方法是在package.json中定义browserslist属性规则进行浏览器兼容性语法补全。
	    options: {
   
	      ident: "postcss",
	      plugins: () => [require("postcss-preset-env")],
	    },
	  },
	],
},
3)处理Less文件:
{
   
  // 处理less文件的规则所需loader安装指令:npm i less-loader -D 和 npm i less -D
  test: /\.less$/,
  use: [
    // "style-loader",
    {
   
      loader: MiniCssExtractPlugin.loader,
      options: {
   
        publicPath: "../../",
      },
    },
    "css-loader",
    "less-loader",
  ],
},
4)处理图片文件:
{
   
   // 处理图片文件的规则安装指令:cnpm i url-loader file-loader  -D
   test: /\.(png|jpe?g|gif|gif|svg)(\?.*)?$/,
   loader: "url-loader",
   options: {
   
     limit: 80 * 1024, // 当图片小于80kb时采用base64的方式打包,大于则以图片形式打包。
     name: "[hash:10].[ext]", // 每次webpack构建打包会生成一串不重复的hash码,[hash:10]则是去hash的前十位,[ext]取源文件的后缀名。
     outputPath: "static/img", // 输出目录,output定义了输出目录为build,此处图片输出目录为build/static/img/XXX文件。
     esModule: false, // 默认使用es6语法解析,html-loader使用的是commonjs语法引入,但2020年09月24日不用关闭url-loader的es6解析方法。
   },
},
5)处理html文件引入的图片:
{
   
  // 处理html中img等标签引入的图片资源所需loader安装指令:npm i html-loader  -D
  test: /\.html$/,
  loader: "html-loader", // 处理url-loader仅能处理打包图片而不能处理html中资源的遗留问题。
},
6)处理字体图标:
{
   
  // 处理引入字体图标资源所需loader安装指令:npm install file-loader -D
  test: /(\.(ttf|woff|eot)$|iconfont\.svg)/,
  loader: "file-loader",
  options: {
   
    name: "[hash:10].[ext]",
    outputPath: "static/font",
  },
},
7)处理JS文件并兼容:
{
   
  /**
   * 处理es6语法转es5语法和Promise等新增属性所需的loader安装指令:npm i babel-loader @babel/preset-env @babel/core @babel/polyfill core-js -D
   * 关于解决Promise等新增技术IE旧(垃)版(圾)浏览器不能识别的问题:
   * 1)入口文件中首行添加import '@babel/polyfill' 引入模块,简单方便,但会引入不必要的兼容配置,造成代码体积偏大。
   * 2)按需加载比较推荐
   */
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    {
   
      /**
       * 开启多进程打包所需loader安装指令:npm install thread-loader -D
       * 可以给每一个规则使用这个loader,但是建议只给js进行,因为js打包花费的时间很多。建议项目足够大时打开多进程打包,开启经常需要600ms,进程通信也有开销。
       */
      // ,
      loader: "thread-loader", // 建议项目足够大时打开多进程打包,开启经常需要600ms,进程通信也有开销。
      options: {
   
        works: 4, // 核数
      },
    },
    {
   
      loader: "babel-loader",
      options: {
   
        presets: [
          // "@babel/preset-env" // 把下面数组的注释掉不会适配Promise等高级技术了,仅仅会转换let、const、箭头函数。
          [
            "@babel/preset-env",
            {
   
              useBuiltIns: "usage",
              corejs: {
   
                version: 3,
              },
              // 兼容范围
              targets: {
   
                chrome: "50",
                firefox: "50",
                ie: "10",
                safari: "10",
                edge: "18",
              },
            },
          ],
        ],
        // 开启JS代码缓存,当文件名不变时,浏览器强制缓存js文件,导致修改的项目不能实时更新,所以应该在output中输出文件名中包含hash值,采用的是[content:10]的根据内容生成hash值的形式。没有采用hash是因为css在js中引入属于同一个chunk,输出时带有同一个hash值。
        cacheDirectory: true,
      },
    },
  ],
},

Plugins

插件(plugins)可以让webpack执行范围更广更为复杂的任务,配置打包优化等一下相关的作用功能,使用前需要单独引入对应的插件。

1)处理html文件插件:
// 无template属性时,默认在输出目录创建一个空的html文件,并将打包后的资源引入其中。template指明文件时,则复制文件,并引入打包后的资源。
new HtmlWebpackPlugin({
   
  template: "./src/index.html",
  minify: {
   
    collapseWhitespace: true, // 清除空行缩进
    removeAttributeQuotes: true, // 清除注释
  },
}),
2)抽离CSS成单独文件插件:
// 处理CSS从js文件中抽离生成独立文件
new MiniCssExtractPlugin({
   
   filename: "static/css/app.css", // 文件输出目录
 }),
3)压缩CSS插件:
// Css压缩插件,需要在package.json中定义sideEffects属性防止它压缩去除掉一些css,less等文件。
new OptimizeCssAssetsWebpackPlugin(),
4)PWA离线访问技术插件:
// PWA离线缓存技术,优化使用体验,网络断开后刷新网页仍能够加载得到已经缓存的资源文件,依靠service Workers技术,插件执行后生成一个servicework配置文件,需要在入口文件中注册,兼容性判断。
new WorkboxWebpackPlugin.GenerateSW({
   
  clientsClaim: true, // 帮助servicework快速启动
  skipWaiting: true, // 删除旧版本使用最新的serviceworker技术
}),
5)忽略库并动态引入第三方库插件:
/**
 * dll动态引入单独库
 * 通过manifest.json文件中的映射关系,构建打包时进行忽略打包哪些库,再通过addAssetHtmlWebpackPlugin引入独立打包的库。
 */
new webpack.DllReferencePlugin({
   
  manifest: resolve(__dirname, "dll/manifest.json"),
}),
new addAssetHtmlWebpackPlugin({
   
  filepath: resolve(__dirname, "dll/jquery.js"),
}),

Mode

配置webpack的工作方式,其中有开发(development)和生产(production)模式,开发环境配置简单,能够使代码能够跑在本地即可,生产模式相关复杂,需要处理网站运行上线时的优化等操作。

// mode: "development",
mode: "production", // 设置webpack的工作环境

开发环境优化

HMR热模块替换

webpack处于开发环境中时,默认是一个模块发生改变,全部模块均会重新加载,为了解决此问题,引入HMR热模块替换,资源发生改变时,仅会重新构建打包发生改变的模块。

1)样式文件会自动热模块替换,因为style-loader内部实现了这个功能。

2)开启HMR后html默认是不会自动更新,入口文件中引入html文件,但默认是不会对html做HMR。

entry: ["./src/main.js", "./index.html"],

3)js代码发生改变默认也不可以发生更新,入口文件中对此进行监听!

// 判断是否开启HRM热模块更新,如果开启则监听所需的js文件,则热模块替换发生作用。
if (module.hot) {
   
  // 对入口文件中引入的依赖进行热部署替换监听
  module.hot.accept("./utils/url.js", () => {
   
    // 一旦监听到发生改变,立即执行该回调函数。
    getUrl();
  });
}

缓存方式提高构建速度

1)babel缓存:

配置处理js的loader设置cacheDirectory:
true,会强制js缓存一定时间,但是会造成开发环境代码改变后,生产环境下代码读取的是缓存中的代码,造成不能实时更新代码的问题。

2)文件资源缓存:

  • hash:webpack每次打包构建时会生成一个唯一的hash值,将打包输出的文件名字中带有hash值,则每次改动,刷新均要请求所有数据。不会读取缓存里的资源,造成了js,css缓存失效。

  • chunkhash:根据打包时引入的chunk生成hash值,如果打包资源来自同一个资源文件件中,hash值就一致,因为css是在js中引入,chunk一致,导致js,变化css也会跟着不会读取缓存。

  • contenthash: 根据文件内容生成hash值,不同引入文件的hash值就不一样。

output: {
   
    filename: "static/js/[name][contenthash:5].js",
    path: resolve(__dirname, "build"),
  },

生产环境优化

Tree Shaking树摇

打包构架去除无用代码,必须是使用ES6模块化引入以及必须指定production环境,自动开启treeshaking模式,减少代码体积。package.json中配置sideEffects: false所有代码均开启树摇模式,但可能会干掉无辜的css等文件。 若标记为sideEffects: ["*.css"]时则不会干掉所匹配的文件。

JS代码懒加载

通过es6语法引入,延时加载,触发一定行为才进行请求加载,不是开局就全部加载进来,那样会增加首次加载的时间,也有着代码分隔的特性,会被单独分割成一个单独文件。

// 动态js引入,单独打包生成一个文件,并给定文件名。也会有懒加载的现象。添加预加载webpackPrefetch关键字。
import(/*webpackChunkName: 'test',webpackPrefetch: true*/ "./test.js")
  .then((res) => {
   
    console.log("文件加载成功", res);
  })

  .catch((err) => {
   
    console.log("文件加载失败", err);
  });

预加载

等其他浏览器空闲了再偷偷加载,请求到文件数据了,触发行为的时候再去读取缓存中的数据,懒加载的方式上添加添加预加载webpackPrefetch关键字。

代码分割code split

1)多入口文件方式分隔,对象多入口形式,生成多个chunk,构建后形成多个js文件,用于代码分隔。

// entry: {
   
//   index: "./src/index.js",
//   test: ["./src/test.js"], // 特殊数组写法
// },

2)optimization配置分隔,将node_modules的库单独分割打包成vendors.js文件。

optimization: {
   
    splitChunks: {
   
      chunks: "all", // 所有配置均为默认
    },
}

3)入口文件中动态js引入的方式,具有懒加载以及会镜像代码分割。

import(/*webpackChunkName: 'add',webpackPrefetch: true*/ "assets/js/add.js")
  .then((res) => {
   
    console.log("文件加载成功", res);
  })

  .catch((err) => {
   
    console.log("文件加载失败", err);
  });

PWA渐进式网络开发应用技术(离线访问)

无网络时,刷新仍然可以访问到已经加载的网页,借助了workbox-webpack-plugin插件进行实现,安装指令:cnpm iworkbox-webpack-plugin -D,且必须运行在服务器中才可以看到结果。

安装静态资源服务器

1)npm install serve -g

2)项目根目录执行指令: serve -s,默认发布打包目录build下的index.html到静态资源服务器。

配置插件

new WorkboxWebpackPlugin.GenerateSW({
   
  clientsClaim: true, // 帮助servicework快速启动
  skipWaiting: true, // 删除旧版本使用最新的serviceworker技术
}),

入口文件作兼容性判断

// 注册serviceWork并处理兼容性问题
if ("serviceWorker" in navigator) {
   
  window.addEventListener("load", () => {
   
    navigator.serviceWorker
      .register("/service-worker.js")
      .then((res) => {
   
        // eslint-disable-next-line
        console.log("注册成功", res);
      })
      .catch((err) => {
   
        // eslint-disable-next-line
        console.log("注册失败", err);
      });
  });
}

Source-Map映射技术

构建后代码到源代码的有一种映射技术,如果构建代码出错了,通过映射关系能找到源代码的位置,非常利于调试代码,但是也会造成代码被盗用的安全性问题。详细参数移步webpack.config.js中查看。

/**
 * Inline-source-map:内联map文件不会单独生成xxx.js.map文件 直接生成一个map信息放在打包后的js文件的最后 构建速度会更快
 * Hidden-source-map:默认设置 生成外部的map信息文件
 * Eval-source-map:同样也是内联map信息 在每一个引入的资源后面均生成一个map信息
 * 参数
 * source-map:错误代码的准确信息和源代码的错误位置 并且能够导出对应的源代码
 * inline-source-map:打印输出的文件位置 可定位到源代码的位置
 * hidden-source-map:打印输出的是打包后的代码 可定位到定位打包后的位置 不可以追溯到源代码的位置
 * eva-source-map:错误和输出信息的准确位置 可追溯到源代码的行列位置
 * nosource-source-map:错误和输出信息的准确位置,不可追溯到源代码的行列位置
 * cheap-source-map:错误和输出信息的准确位置 可追溯到源代码的行位置
 * cheap-module-source-map:错误和输出信息的准确位置 可追溯到源代码的行列位置 会将webpack配置等信息添加进来
*/

直接打包构建项目


1)项目根目录的控制台执行指令:

webpack ./src/index.js -o ./build/built.js–mode=development,开发模式中打包src下的index.js入口文件;输出在build路径下文件名为built.js。

2)打包结果分析:

每次打包都会生成不重复且唯一的hash值,打包构建所用时间以及文件的大小等参数。

配置文件方式构建

项目跟目录下建立webpack.config,js文件,当我们控制台输入webpack打包指令时,默认会按webpack.config.js中的配置去打包构建,配置文件文件通过commomjs的方式暴露一个配置对象。这个就不再分析了,具体看webpack.config.js文件。

webpack.config.js详细配置

const {
    resolve } = require("path"); // 引入node.js的一个path路径模块,通过解构获取到一个resolve属性值,用于获得当前目录的绝对路径。
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 处理html插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 抽离css成单独文件插件
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin"); // 引入压缩Css代码插件
const WorkboxWebpackPlugin = require("workbox-webpack-plugin"); // 引入实现PWA离线缓存技术插件
const TerserWebpackPlugin = require("terser-webpack-plugin"); // 压缩js代码插件
const webpack = require("webpack"); // 引入dll定义属性插件,通过.json映射文件实现忽略单独打包的第三库,在通过addAssetHtmlWebpackPlug进行单独引入。
const addAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin"); // dll单独打包库自动引入html插件

// process.env.NODE_ENV = "production"; // 设置nodejs的进程环境为production生成环境,postcss默认工作于生产环境下。
module.exports = {
   
  entry: "./src/main.js",
  /**
   * 数组形式:数组多入口,构建打包后形成一个chunk,一个js文件。常用于将html文件引入,使其具有HMR热替换功能。
   * 对象形式:对象多入口形式,生成多个chunk,构建后形成多个js文件,用于代码分隔。
   */
  // entry: ["./src/index.js", "./src/test.js"]
  // entry: {
   
  //   index: "./src/index.js",
  //   test: ["./src/test.js"], // 特殊数组写法
  // },
  output: {
   
    filename: "static/js/[name].js",
    path: resolve(__dirname, "build"),
    chunkFilename: "js/[name]~[contenthash:10].js", // 通过懒加Es6懒加载方式和optimization插件进行分割形成的chunk遵循这个命名规则
    library: "[name]Lib", // 构建打包向外暴露名,即调用名。
    libraryTarget: "window", // 绑定到window对象中,很多属性对象。
  },
  module: {
   
    rules: [
      // eslint语法检查
      {
   
        /**
         * js语法所需loader安装指令:npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
         * eslint的js语法检查是依托于airbnb规则进行检查,根据package.json下的eslintConfig的配置进行检测语法。
         * airbnb默认是不能认识window等对象,可通过eslintConfig下的env属性进行屏蔽检查,可通过eslint-disable-next-line注释取消下一行的语法检查。
         */
        test: /\.js$/, // 通过正则匹配后缀名为.js的文件
        enforce: "pre", // 设置loader的执行顺序,pre(优先)| post(延后)。
        exclude: /node_modules/, // 排除node_modules目录下js文件的语法检查
        loader: "eslint-loader", // 指定eslint-loader执行处理js文件进行语法检查
        options: {
   
          fix: true, // 配置参、空格、缩进不规范的语法自动进行修复。
        },
      },
      {
   
        // 当文件流到这个对象时,匹配到一个规则之后就不再向下匹配,优化构建打包速度。
        oneOf: [
          {
   
            // 处理css文件的规则所需loader安装指令:npm i style-loader -D 和 npm i css-loader -D
            test: /\.css$/,
            // 处理文件时使用到多个lorder时,执行顺序为从下到上。
            use: [
              // "style-loader", // 处理创建style标签,将js中处理的资源添加到style标签中,再添加到页面head中生效。
              {
   
                loader: MiniCssExtractPlugin.loader, // 因为css引入js文件中,会造成js代码文件过大,所以通过MiniCssExtractPlugin构造函数自带loader取代style-loader,作用为将css抽离成为单个文件通过link标签引入。
                options: {
   
                  publicPath: "../../", // 资源引入html文件时的路径前缀,因为css文件以及被单独抽离至特定目录下,正确修改才能匹配到css中引用的静态资源。
                },
              },
              // 翻译css使webpack能够识别css样式语法
              "css-loader",
              {
   
                loader: "postcss-loader", // 使用postcss进行浏览器兼容,使用的方法是在package.json中定义browserslist属性规则进行浏览器兼容性语法补全。
                options: {
   
                  ident: "postcss",
                  plugins: () => [require("postcss-preset-env")],
                },
              },
            ],
          },
          {
   
            // 处理less文件的规则所需loader安装指令:npm i less-loader -D 和 npm i less -D
            test: /\.less$/,
            use: [
              // "style-loader",
              {
   
                loader: MiniCssExtractPlugin.loader,
                options: {
   
                  publicPath: "../../",
                },
              },
              "css-loader",
              "less-loader",
            ],
          },
          {
   
            // 处理图片文件的规则安装指令:cnpm i url-loader file-loader  -D
            test: /\.(png|jpe?g|gif|gif|svg)(\?.*)?$/,
            loader: "url-loader",
            options: {
   
              limit: 80 * 1024, // 当图片小于80kb时采用base64的方式打包,大于则以图片形式打包。
              name: "[hash:10].[ext]", // 每次webpack构建打包会生成一串不重复的hash码,[hash:10]则是去hash的前十位,[ext]取源文件的后缀名。
              outputPath: "static/img", // 输出目录,output定义了输出目录为build,此处图片输出目录为build/static/img/XXX文件。
              esModule: false, // 默认使用es6语法解析,html-loader使用的是commonjs语法引入,但2020年09月24日不用关闭url-loader的es6解析方法。
            },
          },
          {
   
            // 处理html中img等标签引入的图片资源所需loader安装指令:npm i html-loader  -D
            test: /\.html$/,
            loader: "html-loader", // 处理url-loader仅能处理打包图片而不能处理html中资源的遗留问题。
          },
          {
   
            // 处理引入字体图标资源所需loader安装指令:npm install file-loader -D
            test: /(\.(ttf|woff|eot)$|iconfont\.svg)/,
            loader: "file-loader",
            options: {
   
              name: "[hash:10].[ext]",
              outputPath: "static/font",
            },
          },
          {
   
            /**
             * 处理es6语法转es5语法和Promise等新增属性所需的loader安装指令:npm i babel-loader @babel/preset-env @babel/core @babel/polyfill core-js -D
             * 关于解决Promise等新增技术IE旧(垃)版(圾)浏览器不能识别的问题:
             * 1)入口文件中首行添加import '@babel/polyfill' 引入模块,简单方便,但会引入不必要的兼容配置,造成代码体积偏大。
             * 2)按需加载比较推荐
             */
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              {
   
                /**
                 * 开启多进程打包所需loader安装指令:npm install thread-loader -D
                 * 可以给每一个规则使用这个loader,但是建议只给js进行,因为js打包花费的时间很多。建议项目足够大时打开多进程打包,开启经常需要600ms,进程通信也有开销。
                 */
                // ,
                loader: "thread-loader", // 建议项目足够大时打开多进程打包,开启经常需要600ms,进程通信也有开销。
                options: {
   
                  works: 4, // 核数
                },
              },
              {
   
                loader: "babel-loader",
                options: {
   
                  presets: [
                    // "@babel/preset-env" // 把下面数组的注释掉不会适配Promise等高级技术了,仅仅会转换let、const、箭头函数。
                    [
                      "@babel/preset-env",
                      {
   
                        useBuiltIns: "usage",
                        corejs: {
   
                          version: 3,
                        },
                        // 兼容范围
                        targets: {
   
                          chrome: "50",
                          firefox: "50",
                          ie: "10",
                          safari: "10",
                          edge: "18",
                        },
                      },
                    ],
                  ],
                  // 开启JS代码缓存,当文件名不变时,浏览器强制缓存js文件,导致修改的项目不能实时更新,所以应该在output中输出文件名中包含hash值,采用的是[content:10]的根据内容生成hash值的形式。没有采用hash是因为css在js中引入属于同一个chunk,输出时带有同一个hash值。
                  cacheDirectory: true,
                },
              },
            ],
          },
        ],
      },
    ],
  },
  // 插件使用需要先引入在new生成实例
  plugins: [
    // 无template属性时,默认在输出目录创建一个空的html文件,并将打包后的资源引入其中。template指明文件时,则复制文件,并引入打包后的资源。
    new HtmlWebpackPlugin({
   
      template: "./src/index.html",
      minify: {
   
        collapseWhitespace: true, // 清除空行缩进
        removeAttributeQuotes: true, // 清除注释
      },
    }),
    // 处理CSS从js文件中抽离生成独立文件
    new MiniCssExtractPlugin({
   
      filename: "static/css/app.css", // 文件输出目录
    }),
    // Css压缩插件
    new OptimizeCssAssetsWebpackPlugin(),

    // PWA离线缓存技术,优化使用体验,网络断开后刷新网页仍能够加载得到已经缓存的资源文件,依靠service Workers技术,插件执行后生成一个servicework配置文件,需要在入口文件中注册,兼容性判断。
    new WorkboxWebpackPlugin.GenerateSW({
   
      clientsClaim: true, // 帮助servicework快速启动
      skipWaiting: true, // 删除旧版本使用最新的serviceworker技术
    }),

    /**
     * dll动态引入单独库
     * 通过manifest.json文件中的映射关系,构建打包时进行忽略打包哪些库,再通过addAssetHtmlWebpackPlugin引入独立打包的库。
     */
    new webpack.DllReferencePlugin({
   
      manifest: resolve(__dirname, "dll/manifest.json"),
    }),
    new addAssetHtmlWebpackPlugin({
   
      filepath: resolve(__dirname, "dll/jquery.js"),
    }),
  ],
  // mode: "development",
  mode: "production", // 设置webpack的工作环境

  // 打包构建忽略打包的库,并通过手动外部CDN引入。
  // externals: {
   
  //   jquery: "jquery",
  // },

  /**
   * 安装指令:npm i webpack-dev-server -D
   * 开发服务器自动编译、自动刷新、自动打开浏览器,只会在内存中编译打包,不会输出代码,本地安装启动指令:npx webpack-dev-server。
   */
  devServer: {
   
    contentBase: resolve(__dirname, "build"), // 运行代码目录
    watchContentBase: true, // 监视contentBase下文件目录,发现文件变化则reload。
    watchOptions: {
   
      ignored: /node_modules/, // 忽略文件
    },
    compress: true, // 采用gzip压缩代码体积会更小
    port: 9527,
    host: "localhost",
    open: true, // 自动打开浏览器
    hot: true, // 开启HMR功能,提高开发环境打包的效率。
    clientLogLevel: "none", // 不需要开启webpack启动日志信息
    quiet: true, // 仅仅显示基本信息
    overlay: true, // 不要全屏显示报错
    proxy: {
   
      "/api": {
   
        // 处于5000端口的devserver接收到/api的请求,会将请求代理转发到3000端口下的服务。
        target: "http://localhost:3000/",
        // 去掉/api,路径替换重写为http://localhost:3000/文件。
        pathRewrite: {
   
          "^/api": "",
        },
      },
    },
  },
  // 解析模块
  resolve: {
   
    alias: {
   
      assets: resolve(__dirname, "src/assets/"), // 设置路径别名
    },
    // extensions: ["js", "css", "vue", "json"], // 引入时可省略的后缀名
    modules: ["node_modules"],
  },
  // 将node_modules里面的库单独打包成一个文件verdor.js,配置项太多了,官网自行查看。
  optimization: {
   
    splitChunks: {
   
      chunks: "all", // 所有配置均为默认
    },
    // 入口文件打包的主构建文件(main)需要引用其他的chunk,打包生成后main会存有其他chunk打包的hash值(使用contenthash方式命名),一旦其他chunk发生改动,main也需要重新打包构建,会造成缓存失效,此配置将main文件中记录其他chunk的hash值打包成为一个单独的文件。再将此文件引入main,达到解耦的效果。
    runtimeChunk: {
   
      name: (entrypoint) => `runtime-${
     entrypoint.name}`,
    },
    // 通过Terser压缩js代码
    minimizer: [
      new TerserWebpackPlugin({
   
        // 开启缓存
        cache: true,
        // 开启多进程打包
        parallel: true,
        // 启用sourceMap,否则会被压缩掉。
        sourceMap: true,
      }),
    ],
  },
  /**
   * 参数
   * source-map:错误代码的准确信息和源代码的错误位置 并且能够导出对应的源代码
   * inline-source-map:打印输出的文件位置 可定位到源代码的位置
   * hidden-source-map:打印输出的是打包后的代码 可定位到定位打包后的位置 不可以追溯到源代码的位置
   * eva-source-map:错误和输出信息的准确位置 可追溯到源代码的行列位置。
   * nosource-source-map:错误和输出信息的准确位置,不可追溯到源代码的行列位置。
   * cheap-source-map:错误和输出信息的准确位置 可追溯到源代码的行位置。
   * cheap-module-source-map:错误和输出信息的准确位置 可追溯到源代码的行列位置 会将webpack配置等信息添加进来
   */
  devtool: "source-map", // 构建后代码到源代码的有一种映射技术,js输出目录下回多出一个xxx.js.map文件,如果构建代码出错了,通过映射关系能找到源代码的位置,非常利于调试代码,但是也会造成代码被盗用的安全性问题。
};

package.json详细配置

{
   
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
   
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
   
    "@babel/core": "^7.11.6",
    "@babel/polyfill": "^7.11.5",
    "@babel/preset-env": "^7.11.5",
    "add-asset-html-webpack-plugin": "^3.1.3",
    "babel-loader": "^8.1.0",
    "core-js": "^3.6.5",
    "css-loader": "^4.3.0",
    "eslint": "^7.9.0",
    "eslint-config-airbnb-base": "^14.2.0",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-import": "^2.22.0",
    "file-loader": "^6.1.0",
    "html-loader": "^1.3.1",
    "html-webpack-plugin": "^4.5.0",
    "jquery": "^3.5.1",
    "less": "^3.12.2",
    "less-loader": "^7.0.1",
    "mini-css-extract-plugin": "^0.11.2",
    "optimize-css-assets-webpack-plugin": "^5.0.4",
    "postcss-loader": "^3.0.0",
    "postcss-preset-env": "^6.7.0",
    "style-loader": "^1.2.1",
    "terser-webpack-plugin": "^4.2.2",
    "thread-loader": "^3.0.0",
    "url-loader": "^4.1.0",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0",
    "workbox-webpack-plugin": "^5.1.4"
  },
  "browserslist": {
   
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
  },
  "eslintConfig": {
   
    "extends": "airbnb-base",
    "env": {
   
      "brower": true
    }
  },
  "sideEffects": [
    "*.css"
  ]
}

寄语

一篇肝了好久的webpack,篇幅很长再加上个人理解可能会有瑕疵,希望大牛别喷,给出的详细webpack.config.js文件我也已经测试过了,我写了很详细的注释,希望能帮到大家!但是如果转载的话希望大家也能注明一下出处!

支持

个人开发了一个资源网址导航网站,很多资源分享,vue项目第一次进会慢一些些,但是过后就很快了,涵盖了生活的方方面面,认真逛逛绝对会有收获,无广告且有软件分享。希望大家支持一下!n.huasenjio.top,如果进不出意外的话我会把这个开源给大家!大家的访问也许对我就是一种鼓励了,谢谢大家!


转载:https://blog.csdn.net/L184820911/article/details/108885442
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场