IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> webpack5【知识大汇总】 -> 正文阅读

[JavaScript知识库]webpack5【知识大汇总】

目录

一、CSS 兼容(处理.css文件、.less文件)

二、打包图片

三、webpack插件使用


https://www.webpackjs.com/concepts/configuration/webpack5 配置官方网站:https://www.webpackjs.com/concepts/configuration/?

webpack5 插件官方网站:https://webpack.docschina.org/loaders/?

一、CSS 兼容(处理.css文件、.less文件)

1、需要下载的的依赖

  • postcss、postcss-cli、postcss-loader:是一个用 JavaScript 工具和插件转换 CSS 代码的工具,postcss-loader 使用?PostCSS?处理 CSS 的 loader
    • 配置?postcss.config.js
    • module.exports = {
        plugins: [
          [
            'postcss-preset-env',
            {
              // 其他选项
            },
          ],
        ],
      };
  • autoprefixer:自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀
  • postcss-preset-env:帮你将最新的 CSS 语法转换成大多数浏览器都能理解的语法,并根据你的目标浏览器或运行时环境来确定你需要的 polyfills,此功能基于?cssdb?实现

  • css-loader:css-loader会对@import 和 url 进行处理

  • less、less-loader:将 Less 编译为 CSS 的 loader

  • style-loader:把 CSS 插入到 DOM 中

  • 配置 webpack.config.js

  • const path = require('path')
    
    module.exports = {
      entry: './src/index.js',
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                // 启用/禁用或者设置在 css-loader 前应用的 loader 数量
                  importLoaders: 1 
                  // 0 => no loaders (默认);
                  // 1 => postcss-loader;
                }
              },
              'postcss-loader'
            ]
          },
          {
            test: /\.less$/,
            use: [
              'style-loader',
              'css-loader',
              'postcss-loader',
              'less-loader'
            ]
          }
        ]
      }
    }
  • 配置 .browserslistrc
  • > 0.01% 
    last 2 version
    not dead

?二、打包图片

?1、img src 三种写法:

  • 使用 require 导入图片,此时如果不配置 esModule: false ,则需.default 导出

    • // img.js
      
      function packImg() {
        // 01 创建一个容器元素
        const oEle = document.createElement('div')
      
        // 02 创建 img 标签,设置 src 属性
        const oImg = document.createElement('img')
        oImg.width = 600
        oImg.src = require('../img/01.wb.png').default
       
        oEle.appendChild(oImg)
      
        return oEle
      }
      
      document.body.appendChild(packImg())
      
  • 在配置当中设置 esModule: false

    • // img.js
      
      function packImg() {
        // 01 创建一个容器元素
        const oEle = document.createElement('div')
      
        // 02 创建 img 标签,设置 src 属性
        const oImg = document.createElement('img')
        oImg.width = 600
        oImg.src = require('../img/01.wb.png')
       
        oImg.src = oImgSrc
        oEle.appendChild(oImg)
      
        return oEle
      }
      
      document.body.appendChild(packImg())
      
      // webpack.json.js
      
      const path = require('path')
      
      module.exports = {
        entry: './src/index.js',
        output: {
          filename: 'main.js',
          path: path.resolve(__dirname, 'dist')
        },
        module: {
          rules: [
            {
              test: /\.(png|svg|jpe?g|gif)$/,
              use: [
                {
                  loader: 'file-loader',
                  options: {
                    esModule: false // 不转为 esModule
                  }
                }
              ]
            }
          ]
        }
      }
  • 采用 import xxx from 图片资源,此时可以直接使用 xxxx

    • // img.js
      
      import oImgSrc from '../img/01.wb.png'
      
      function packImg() {
          // 01 创建一个容器元素
          const oEle = document.createElement('div')
        
          // 02 创建 img 标签,设置 src 属性
          const oImg = document.createElement('img')
          oImg.width = 600
      
          oImg.src = oImgSrc
          oEle.appendChild(oImg)
        
          return oEle
        }
        
        document.body.appendChild(packImg())
      
      

2、?background url 写法

  • img.js
    • import oImgSrc from '../img/01.wb.png'
      import '../css/img.css'
      
      function packImg() {
          // 01 创建一个容器元素
          const oEle = document.createElement('div')
        
          // 02 创建 img 标签,设置 src 属性
          const oImg = document.createElement('img')
          oImg.width = 600
      
          oImg.src = oImgSrc
          oEle.appendChild(oImg)
        
          // 03 设置背景图片
          const oBgImg = document.createElement('div')
          oBgImg.className = 'bgBox'
          oEle.appendChild(oBgImg)
        
          return oEle
        }
        
        document.body.appendChild(packImg())
      
      

  • ?设置webpac.config.js 中 css-loader的options的 esModule: false
    • // webpack.config.js
      
      const path = require('path')
      
      module.exports = {
        entry: './src/index.js',
        output: {
          filename: 'main.js',
          path: path.resolve(__dirname, 'dist')
        },
        module: {
          rules: [
            {
              test: /\.css$/,
              use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                    importLoaders: 1,
                    esModule: false
                  }
                },
                'postcss-loader'
              ]
            },
            {
              test: /\.(png|svg|jpe?g|gif)$/,
              // use: [
              //   {
              //     loader: 'file-loader',
              //     options: {
              //       esModule: false // 不转为 esModule
              //     }
              //   }
              // ]
              use: ['file-loader']
            }
          ]
        }
      }

3、设置打包图片的输出名称和路径名,配置如下:

// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              /**
                 * [ext]: 扩展名
                 * [name]: 文件名
                 * [hash]: 文件内容
                 * [contentHash]:
                 * [hash:<length>]
                 * [path]:
              */  
              name: 'img/[name].[hash:8].[ext]',
              // outputPath: 'img' // 或者在 name 直接添加 img/
            }
          }
        ]
      }
    ]
  }
}

4、url-loader?

  • url-loader 是将图片转化为 base64 ,加载到 js文件中,优点是减少请求的次数,缺点是图片大的话,加载速度慢
  • file-loader是将图片拷贝到指定的目录,优点是大图片请求速度快,缺点是增加请求次数

  • url-loader 内部其实也可以调用 file-loader,二者可以结合使用,使用 limit 配置

// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpe?g|gif)$/,
         use: [
          {
            loader: 'url-loader',
            options: {
              name: 'img/[name].[hash:6].[ext]',
              limit: 25 * 1024
            }
          }
        ]
      }
    ]
  }
}

5、type:assset (webpack5 内置模块)处理图片替换 filse-loader 和 url-loader 使用

  • asset/resource? 相当于 fille-loader 作用
// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset/resource',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        }
      }
    ]
  }
}
  • asset/inline? 相当于 url-loader 作用
// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset/inline'
      }
    ]
  }
}
  • asset/source 相当于 row-loader 作用很少用
  • asset:通过限制图片大小的尺寸,进行拷贝图片或者将图片转为 base64
// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      }
    ]
  }
}

?

6、asset 处理字体图标

设置 type 类型为 asset/resource

// webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  }
}

三、webpack插件使用

1、clean-webpack-plugin 清空上一次的打包结果

// webpack.config.js

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}

2、html-webapck-plugin?:内置 html模板,设置自定义属性?title 、template

// webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'html-webpack-plugin',
      template: './public/index.html'
    })
  ]
}

3、DefinePlugin(webpack 内置模块):用于定义全局变量(?link 引用的 BASE_url)

// html 模板

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">

  <link rel="icon" href="<%= BASE_URL %>favicon.ico">

  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>

</html>
// webpack.config.js

const path = require('path')
const { DefinePlugin } = require('webpack')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new DefinePlugin({
      BASE_URL: '"./"'
    })
  ]
}

4、copy-webpack-plugin:拷贝静态资源到打包目录

// webpack.config.js

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html'] // 忽略 index.html
          }
        }
      ]
    })
  ]
}

5、babel (解决 JSX、ES6、TS的语法转换)

需要安装的依赖:

  • @babel/cli:使用 babel命令
  • @babel/core:转换语法核心插件
  • @babel/preset-env:预设的 babel 插件集合
  • babel-loader
// webpack.config.js

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.js$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html'] // 忽略 index.html
          }
        }
      ]
    })
  ]
}
// 单独配置babel的转换机制
// babel.config.js

module.exports = {
    presets: [
        '@babel/preset-env',
        // { targets: 'chrome 91' } // 兼容谷歌的版本
    ]
}

6、polyfill :转换 Promise语法新特性,打一些补丁和做一些填充

  • @babel/polyfill 不建议安装,包太大,可以安装核心插件:core-js、regenerator-runtime?
  • 在 index.js 引入?core-js、regenerator-runtime?
// index.js

import "core-js/stable";
import "regenerator-runtime/runtime";

const title = '拉钩教育'
const foo = () => {
    console.log(title)
}
const p1 = new Promise((resolve, reject) => {
    console.log(111)
  })
  console.log(p1)
foo()
  • 配置 babe.config.js
// babel.config.js

module.exports = {
    "presets": [
        ["@babel/preset-env", {
        // false: 不对当前的JS处理做 polyfill 的填充
        // usage: 依据用户源代码当中所使用到的新语法进行填充
        // entry: 依据我们当前筛选出来的浏览器决定填充什么
        "useBuiltIns": "entry",
        "corejs": 3
        }]
    ]
}

  • 配置 webpack.config.js
// webpack.config.js

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        type: 'asset',
        // 可在 generator配置 或者在 output配置 assetModuleFilename: "img/[name].[hash:4][ext]"
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html'] // 忽略 index.html
          }
        }
      ]
    })
  ]
}

7、webpack-dev-server 热更新

  • 添加 watch 监听,live serve 热启动

(1)方式一:在build 添加 --watch

// package.json  

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config lg.webpack.js --watch"
  },

?? (2)方式二:在 webpack.json.js 添加 watch 属性为 true?

// webpack.config.js

module.exports = {
  watch: true,
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  ......
}
  • 安装依赖?webpack-dev-server,添加 serve 属性
// webpack.config.js  

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config lg.webpack.js",
    "serve": "webpack serve --config lg.webpack.js"
  },

?(3)二者监听的对比

????????watch 监听不足:

  • 所有源代码都会被重新编译
  • 每次编译成功之后需要进行文件读写
  • 不能实现局部刷新

????????webpack-dev-server

  • 可以实现局部刷新
  • 编译后的文件在内存中,读取速度快
  • 开启一个服务端

8、?webpack-dev-middleware :如果相对打包监听使用自由度高,可使用这个依赖

  • yarn add express?webpack-dev-middleware -D
  • 在根目录新建 Serve.js文件
  • // Server.js
    
    const express = require('express')
    const webpackDevMiddle = require('webpack-dev-middleware')
    const webpack = require('webpack')
    
    const app = express()
    
    // 获取配置文件
    const config = require('./webpack.config.js')
    const compiler = webpack(config)
    
    app.use(webpackDevMiddle(compiler))
    
    // 开启端口上的服务
    app.listen(3000, () => {
        console.log('服务运行在 3000 端口上');
    })
  • node .\Server.js?

9、HMR :开启模块热更新(已安装 webpack-dev-server 情况下使用)

  • 配置 webpack.config.js,添加 devServe 属性
// webpack.config.js

module.exports = {
  mode: 'development',
  devtool: false,
  devServer: {
    hot: true
  },
  ......
}
  • 在 index.js 中对想要热更新的文件进行? module.js 判断
// index.js

import './title'

if (module.hot) {
    module.hot.accept(['./title.js'], () => {
        console.log('title.js模块更新');
    })
}

10、react 使用热更新

  • yarn add @pmmmwh/react-refresh-webpack-plugin react-refresh -D
  • 配置 .babel.config.js
// babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env'],
    ['@babel/preset-react'],
  ],
  plugins: [
    ['react-refresh/babel']
  ]
}
  • 配置 webpack.config.js?,引入插件?@pmmmwh/react-refresh-webpack-plugin
// webpack.config.js

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  devServer: {
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: '"./"'
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new ReactRefreshWebpackPlugin()
  ]
}

11、vue? 使用 HRM

  • yarn add?vue-loader?vue-template-compiler?-D // vue2建议安装 vue-loader@14 以下版本,vue3安装?ue-loader@15 以上版本,15版本之前的不需要处理 .vue 文件,15之后需要手动处理安装插件vue-loader/lib/plugin
  • 配置 webpack.config.js,引入插件?vue-loader/lib/plugin
// webpack.config.js

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  devServer: {
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: '"./"'
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new VueLoaderPlugin()
  ]
}

12、output 中的 path?

// webpack.config.js

module.exports = {
  mode: 'development',
  devtool: false,
  devServer: {
    hot: true
  },
  entry: './src/index.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist'),
    // assetModuleFilename: "img/[name].[hash:4][ext]"
    publicPath: './'
  },
  ......
}

13、?devserver 中的 path?

  • publicPath:指定本地服务所在的目录
  • contentBase:我们打包后的资源如果依赖其他资源?,词是告知去哪里去找
  • watchContentBase:监听引入资源变化的内容
// webpack.config.js

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  devServer: {
    hot: true,
    publicPath: '/lg',
    contentBase: path.resolve(__dirname, 'public'),
    watchContentBase: true
  },

  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/lg'
  },
  ......
}

14、devServer 常用配置

  • hot: true 开启热更新
  • hotOnly: true 只对更新的加载
  • port: 4000 设置端口号
  • open: true 服务启动,自动开启浏览器
  • compress: true 压缩 js
  • historyApiFallback: true 设置回退历史纪录
  • proxy:解决跨域问题
    • 
      module.exports = {
        mode: 'development',
        devtool: false,
        entry: './src/index.js',
        devServer: {
          hot: true,
          publicPath: '/lg',
          contentBase: path.resolve(__dirname, 'public'),
          watchContentBase: true,
          proxy: {
            '/api': {
              target: 'https://api.github.com',
              pathRewrite: { "^/api": "" },
              changeOrigin: true
            }
          }
        },
        ......
      }

15、resolve: 模块路径解析规则,对于引入的文件进行后缀名补全设置

// webpack.config.js

module.exports = {
  mode: 'development',
  devtool: false,
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'], 
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  ......
}

16、source-map:方便定位源代码位置

  • 设置 mode:“development” //? 默认是 none,production是开发模式
  • 设置 devtool:"source-map" // eval |?cheap-eval-source-map ...

17、ts-loader 和 babel-loader 对 .ts文件进行转换编译?

?ts-loader:打包时不能对 ES6 新语法进行填充,不建议使用

  • yarn add ts-loader -D
  • 配置 webpack.config.js 规则?
// webpack.config.js

module.exports = {
  mode: 'development',
  entry: './src/index.ts',
  devtool: 'nosources-source-map',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  devServer: {
    hot: true,
    port: 4000
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      },
      {
        test: /\.ts$/,
        use: ['ts-loader']
      }
    ]
  },
  ......
}

?babel-loader:打包时能够补充 ES6 新语法

  • .babel.config.js配置
// babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3
    }],
    ['@babel/preset-typescript']
  ]
}
  • webpack.config.js 配置
// webpack.config.js

module.exports = {
  mode: 'development',
  entry: './src/index.ts',
  devtool: 'nosources-source-map',
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  devServer: {
    hot: true,
    port: 4000
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      },
      {
        test: /\.ts$/,
        use: ['babel-loader']
      }
    ]
  },
  ......
}
  • package.json.js 配置命令
// package.json.js  

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "npm run ck && webpack",
    "serve": "webpack serve",
    "ck": "tsc --noEmit"
  },

18、加载 vue 文件

  • yarn add vue vue-loader??vue-template-compiler -D
  • 配置 postcss.config.js
// postcss.config.js

module.exports = {
  plugins: [
    require('postcss-preset-env')
  ]
}
  • 配置 webpack.config.js
// webpack.config.js

const path = require('path')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  devtool: false,
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  devServer: {
    hot: true,
    port: 4000
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2
            }
          },
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      },
      {
        test: /\.ts$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: '"./"'
    }),
    new VueLoaderPlugin()
  ]
}

19、合并生产环境配置?

  • ?新建 config目录,新建文件 path.js、webpack.common.js、webpack.dev.js、webpack.prod.js
  • path.js
// path.js

const path = require('path')

const appDir = process.cwd()

const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath)
}

module.exports = resolveApp
  • webpack.common.js
// webpack.common.js

const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')

// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: './src/index.js',  // 反而没有报错( 相对路径 )
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/main.js',
    path: resolveApp('./dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    })
  ]
}

module.exports = (env) => {
  const isProduction = env.production

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

  const mergeConfig = merge(commonConfig, config)

  return mergeConfig
}
  • webpack.dev.js
// webpack.dev.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-source-map',
  target: 'web',
  devServer: {
    hot: true,
    hotOnly: true,
    port: 4000,
    open: false,
    compress: true,
    historyApiFallback: true,
    proxy: {
      '/api': {
        target: 'https://api.github.com',
        pathRewrite: { "^/api": "" },
        changeOrigin: true
      }
    }
  },
  plugins: [
    new ReactRefreshWebpackPlugin()
  ]
}
  • webpack.prod.js
// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'production',
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    })
  ]
}
  • ?babel.config.js
// babel.config.js

const presets = [
  ['@babel/preset-env'],
  ['@babel/preset-react'],
]

const plugins = []

console.log(process.env.NODE_ENV, '<------')

// 依据当前的打包模式来决定plugins 的值 
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
  plugins.push(['react-refresh/babel'])
}

module.exports = {
  presets,
  plugins
}
  • package.json
// package.json  

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "serve": "webpack serve",
    "build2": "webpack --config ./config/webpack.common.js --env production",
    "serve2": "webpack serve --config ./config/webpack.common.js --env development"
  },
  • yarn run build2
  • yarn run serve2

20、?代码拆分方式

  • 多入口打包方式
// webpack.common.js

const commonConfig = {
  entry: {
    main1: './src/main1.js',
    main2: './src/main2.js'
  },
  output: {
    filename: 'js/[name].build.js',
    path: resolveApp('./dist')
  },
  ......
}
  • 通过 import 方式打包,如果入口文件引入依赖 lodash 和 jquery ,写法如下
// main1.js

import _ from 'lodash'
import $ from 'jquery'

console.log($)
console.log('main1.js文件')
console.log(_.join(['前端', '开发']))
// main2.js

import _ from 'lodash'
import $ from 'jquery'

console.log($)

console.log('main2.js文件')
console.log(_.join(['111', '2---']))
// webpack.common.js

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: {
    // 如果 入口文件中引入单个依赖(lodash、jquery)写法
    main1: { import: './src/main1.js', dependOn: 'lodash' },
    main2: { import: './src/main2.js', dependOn: 'lodash' },
    lodash: 'lodash'
    
    // 如果 入口文件中引入多个依赖(lodash、jquery)写法
    // main1: { import: './src/main1.js', dependOn: 'shared' },
    // main2: { import: './src/main2.js', dependOn: 'shared' },
    // shared: ['lodash', 'jquery']
  },
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/[name].build.js',
    path: resolveApp('./dist')
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
}
  • 通过设置 spiltChunks 进行分类打包
// index.js 

import 'jquery'

console.log('index.js代码')
// webpack.common.js

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: {
    index: './src/index.js'
  },
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/[name].build.js',
    path: resolveApp('./dist')
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ],
    splitChunks: {
      chunks: 'all', // 默认是 async(处理异步) | initial(处理同步) | all(同步异步都处理)
      miniSize:2000, // 默认是 2000,如果拆包的体积达不到 2000,就不进行拆包
      maxSize: 2000, // 默认是 0,一般写和miniSize一样,避免出现警告
      minChunks: 1, // 拆分的包至少被引用1次,如果是2 ,不建议和 miniSize、maxSize一起用
      cacheGroups: { // 将引入的第三方依赖包进行合并打包
           syVendors: {
                test: /[\\/]node_modules[\\/]/,
                filename: 'js/[id]_vendors.js',
                priority: -10 // 优先级哪个数值大,用哪个
            },
            default: {
                minChunks: 2, 
                filename: 'js/syy_[id]_vendors.js',
                priority: -20
            }
           
        }
    }
}

21、import 动态导入配置

// webpack.common.js

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: {
    index: './src/index.js'
  },
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/[name].build.js',
    path: resolveApp('./dist'),
    chunkFilename: 'js/chunk_[name]:[contenthash:8].js' // 定义打包名
  },
  optimization: {
    // nature:当前文件的名称按照自然数进行编号排序,如果某个文件当前次不被依赖导入,那么重新打包的次数会变,会影响浏览器的缓存,不建议使用
    // named:一般开发环境下使用,用文件名命名
    // deterministic:生产模式下使用,用文件名产生的 hash 来命名
    chunkIds: 'nature', 
    runtimeChunk: true, // 针对改变的文件进行打包,打包名不边
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
  }
}

用魔法注释可以让打包名包括原文件名:

// index.js

import(/*webpackChunkName: "title"*/'./title')

console.log('index.js代码')

22、代码懒加载、prefetch(预获取) 与 preload(预加载)

// index.js

const oBtn = document.createElement('button')
oBtn.innerHTML = '点击加载元素'
document.body.appendChild(oBtn)

// 按需加载
oBtn.addEventListener('click', () => {
  import(
    /*webpackChunkName:'utils' */

     // 在浏览器空闲的时候预获取,一般这个用的比较多
    /*webpackPreLoad:true */ 

    // 与 chunk 并行下载
    /*webpackPreLoad:true */
    './utils').then(({ default: element }) => {
      console.log(element)
      document.body.appendChild(element)
    })
})
// utils.js

const oEle = document.createElement('div')
oEle.innerHTML = '前端开发'
module.exports = oEle

23、?第三方扩展设置 CDN?

  • 有 CDN服务器情况下,设置?publicPath
// webpack.config.js 

 module.exports ={
    output: {
        filename: 'js/[name].[contenthash:8].bundle.js',
        path: resolveApp('./dist'),
        publicPath: 'https//abc/cdn'
    },
    ......
}
  • 通过在 index.html 引入第三方依赖包 cdn地址来提高访问速度
// index.html

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">

  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>

</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
</body>

</html>
// webpack.config.js  

const commonConfig = {
   // 不打包 lodash
    externals: {
        lodash: '_'
    },
    ......
  }

24、打包 Dll 动态库(将不经常变动的库单独进行打包,这样编译时不再进行打包,提高开发效率)?

  • ?package.json配置 dll 命令
// pageage.json

{
  "name": "46_webpack_pack_dll",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dll": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "webpack": "^5.50.0",
    "webpack-cli": "^4.7.2"
  }
}
  • webpackageconfig.js配置
// webpackage.config.js

const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  mode: "production",
  entry: {
    react: ['react', 'react-dom']
  },
  output: {
    path: path.resolve(__dirname, 'dll'),
    filename: 'dll_[name].js',
    library: 'dll_[name]'
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false
      }),
    ],
  },
  plugins: [
    new webpack.DllPlugin({
      name: 'dll_[name]',
      path: path.resolve(__dirname, './dll/[name].manifest.json')
    })
  ]
}
  • yarn run dll

25、使用 Dll 库:将不常用的依赖包单独打包

  • ?配置 webpack.config.js,添加依赖包?add-asset-html-webpack-plugin
// webpack.config.js

const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')
const TerserPlugin = require('terser-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')

// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: {
    index: './src/index.js'
  },
  resolve: {
    extensions: ['.js', '.json', '.wasm', '.jsx', '.ts', '.vue']
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false
      })
    ],
    runtimeChunk: false,
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 20000,
      minChunks: 1,
      cacheGroups: {
        reactVendors: {
          test: /[\\/]node_modules[\\/]/,
          filename: 'js/[name].vendor.js'
        }
      }
    }
  },
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/[name].[contenthash:8]._bundle.js',
    path: resolveApp('./dist'),

  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    }),
    new webpack.DllReferencePlugin({
      context: resolveApp('./'),
      manifest: resolveApp('./dll/react.manifest.json')
    }),
    new AddAssetHtmlPlugin({
      outputPath: 'js',
      filepath: resolveApp('./dll/dll_react.js')
    })
  ]
}

module.exports = (env) => {
  const isProduction = env.production

  process.env.NODE_ENV = isProduction ? 'production' : 'development'

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

  const mergeConfig = merge(commonConfig, config)

  return mergeConfig
}

26、CSS 抽离(mini-css-extract-plugin)和 压缩(css-minimizer-webpack-plugin)

  • yarn add?mini-css-extract-plugin?css-minimizer-webpack-plugin -D
// paths.js

const path = require('path')

const appDir = process.cwd()

const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath)
}

module.exports = resolveApp

// webpack.common.js

const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')

// 定义对象保存 base 配置信息
const commonConfig = (isProduction) => {
  return {
    entry: {
      index: './src/index.js'
    },
    resolve: {
      extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
      alias: {
        '@': resolveApp('./src')
      }
    },
    output: {
      filename: 'js/[name].[contenthash:8].bundle.js',
      path: resolveApp('./dist'),
    },
    optimization: {
      runtimeChunk: true,
      minimizer: [
        new TerserPlugin({
          extractComments: false,
        }),
      ]
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            {
              loader: 'css-loader',
              options: {
                importLoaders: 1,
                esModule: false
              }
            },
            'postcss-loader'
          ]
        },
        {
          test: /\.less$/,
          use: [
            'style-loader',
            'css-loader',
            'postcss-loader',
            'less-loader'
          ]
        },
        {
          test: /\.(png|svg|gif|jpe?g)$/,
          type: 'asset',
          generator: {
            filename: "img/[name].[hash:4][ext]"
          },
          parser: {
            dataUrlCondition: {
              maxSize: 30 * 1024
            }
          }
        },
        {
          test: /\.(ttf|woff2?)$/,
          type: 'asset/resource',
          generator: {
            filename: 'font/[name].[hash:3][ext]'
          }
        },
        {
          test: /\.jsx?$/,
          use: ['babel-loader']
        }
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        title: 'copyWebpackPlugin',
        template: './public/index.html'
      })
    ]
  }
}

module.exports = (env) => {
  const isProduction = env.production

  process.env.NODE_ENV = isProduction ? 'production' : 'development'

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

  const mergeConfig = merge(commonConfig(isProduction), config)

  return mergeConfig
}
// webpack.dev.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-source-map',
  target: 'web',
  devServer: {
    hot: true,
    hotOnly: true,
    port: 4000,
    open: false,
    compress: true,
    historyApiFallback: true,
    proxy: {
      '/api': {
        target: 'https://api.github.com',
        pathRewrite: { "^/api": "" },
        changeOrigin: true
      }
    }
  },
  plugins: [
    new ReactRefreshWebpackPlugin()
  ]
}
// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")

module.exports = {
  mode: 'production',
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[hash:8].css'
    })
  ]
}

27、TerserPlugin 压缩 JS:在生产模式下使用 (terser-webpack-plugin)

webpack v5 开箱即带有最新版本的?terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装?terser-webpack-plugin。如果使用 webpack v4,则必须安装?terser-webpack-plugin?v4 的版本。?

// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const TerserPlugin = require("terser-webpack-plugin")

module.exports = {
  mode: 'production',
  optimization: {
    minimize: true,
    minimizer: [
      new CssMinimizerPlugin(),
      new TerserPlugin({
        extractComments: false
      })
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[hash:8].css'
    })
  ]
}

28、?scope hoisting:作用域提升,打包构建后可以提升访问速度(是webpack内置功能)

?ModuleConcatenationPlugin插件

// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')

module.exports = {
  mode: 'production',
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
}

29、TreeShaking:打包删除没有用到的函数

  • ?usedExports 配置,配合minimizer、minimize使用?
// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  mode: 'development',
  devtool: false,
  optimization: {
    usedExports: true, // 标记不使用的函数
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    // new webpack.optimize.ModuleConcatenationPlugin()
  ]
}
// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  mode: 'development',
  devtool: false,
  optimization: {
    usedExports: true,
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    // new webpack.optimize.ModuleConcatenationPlugin()
  ]
}
  • ?sideEffects :删除不用的代码

?针对 js 文件写法:

// package.json

{
  "sideEffects": [
    "./src/title.js"  // 删除未引用的代码不包含 title.js
  ]
}

针对 css 文件写法:

// webpack.config.js

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: {
    index: './src/index.js'
  },
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/[name].[contenthash:8].bundle.js',
    path: resolveApp('./dist'),
  },
  optimization: {
    runtimeChunk: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ],
        sideEffects: true,
      }
     ......
    ]
}

30、Css-TreeShaking:对 CSS 没用到的样式内容进行删除

  • yarn add?purgecss-webpack-plugin?glob -D
  • webpack.prod.js 配置
// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const resolveApp = require('./paths')
const glob = require('glob')

module.exports = {
  mode: 'development',
  devtool: false,
  optimization: {
    usedExports: true, // 标记不被使用的函数
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    }),
    new PurgeCSSPlugin({
      paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
      safelist: function () {
        return {
          standard: ['body', 'html', 'ef']
        }
      }
    })
  ]
}

31、?资源压缩?(yarn add compression-webpack-plugin -D)

// webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const CompressionPlugin = require("compression-webpack-plugin")
const resolveApp = require('./paths')
const glob = require('glob')

module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true, // 标记不被使用的函数
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    }),
    new PurgeCSSPlugin({
      paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
      safelist: function () {
        return {
          standard: ['body', 'html', 'ef']
        }
      }
    }),
    new CompressionPlugin({
      test: /\.(css|js)$/, // 对 css 和 js 文件进行压缩
      minRatio: 0.8, //压缩前体积/压缩后体积
      threshold: 0,
      algorithm: 'gzip' // 压缩格式
    })
  ]
}

32、inlineChunkHtmlPlugin 使用:适用于打包的 js文件不大情况下使用,将打包的文件注入到 html????????

// webpack.prod.js


const InlineChunkHtmlPlugin = require('inline-chunk-html-plugin')

module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true, // 标记不被使用的函数
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])
  ]
}

33、webpack 打包 Library?

// webpack.config.js

const path = require('path')

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    filename: 'sy_utils.js', // 打包文件输出名
    path: path.resolve(__dirname, 'dist'),
    libraryTarget: 'umd', // 对 ESModule 、 AMD、CMD 进行暴露
    library: 'syUtil',  // 输出一个库,为你的入口做导出
    globalObject: 'this' // 将打包的文件 self 改成 this
  }
}

34、打包时间和内容分析

  • 打包时间插件:speed-measure-webpack-plugin
// webpack.common.js


// 时间分析
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()


// 定义对象保存 base 配置信息
const commonConfig = (isProduction) => {
  return {
    entry: {
      index: './src/index.js'
    },
   ......
  }
}

module.exports = (env) => {
  const isProduction = env.production

  process.env.NODE_ENV = isProduction ? 'production' : 'development'

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

  const mergeConfig = merge(commonConfig(isProduction), config)

  return smp.wrap(mergeConfig)
}
  • 打包内容分析插件:webpack-bundle-analyzer
 // webpack.prod.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
  mode: 'production',
  ......
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-31 23:55:34  更:2022-03-31 23:59:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:50:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码