Webpack5 基础使用笔记

  • Webpack5 基础使用笔记已关闭评论
  • 85 次浏览
  • A+
所属分类:Web前端
摘要

[webpack中文文档](概念 | webpack 中文文档 | webpack中文文档 | webpack中文网 (webpackjs.com)):

Webpack5 基础使用笔记

[webpack中文文档](概念 | webpack 中文文档 | webpack中文文档 | webpack中文网 (webpackjs.com)):

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

这篇笔记主要记录的是Webpack 5

基本使用

安装

安装webpack的同时需要安装webpack-cli。

npm i webpack webpack-cli -D 

启动

启动分为开发模式和生产模式。

  • 开发模式
npx webpack /path/to/main.js --mode=development 
  • 生产模式
npx webpack /path/to/main.js --mode=production 

其中:

  • npx webpack:用于运行本地安装的webpack;
  • /path/to/main.js:指定webpack从main.js开始打包,会同时打包其依赖文件;
  • --mode=xxx:指定模式。

如果终端输出webpack is not recognized as an internal or external command,即无法被识别为指令。

那么可以考虑将webpack进行全局安装:

npm i -g webpack webpack-cli 

输出

webpack会默认将文件打包输出到dist文件夹,并且只能处理js资源。

如果需要处理其它资源文件,或者需要更精细化地打包,则需要设置webpack的配置文件:webpack.config.js


Webpack的配置

webpack的配置文件命名为webpack.config.js,置于项目文件的根路径下。

webpack是基于node运行的,所以webpack.config.js采用CommonJS模块化规范。

webpack的配置有五大核心概念:

  1. entry(入口):webpack从这个文件开始进行打包,并打包其依赖文件;
  2. output(输出):决定了webpack打包后的文件的文件名、地址等;
  3. loader(加载器):webpack只能处理js文件,其它文件比如css文件、图片资源、jsx文件,需要使用loader才能解析;
  4. plugins(插件):扩展webpack的功能,每一个插件如何配置取决于插件的提供者如何设计;
  5. mode(模式):主要有两种模式,开发模式(development)和生产模式(production)。

简单的配置文件样例

// Node.js的核心模块,专门用来处理文件路径 const path = require("path");  module.exports = {   // 入口   // 相对路径和绝对路径都行   entry: "./src/main.js",   // 输出   output: {     // path: 文件输出目录,必须是绝对路径     // path.resolve()方法返回一个绝对路径     // __dirname 当前文件的文件夹绝对路径     path: path.resolve(__dirname, "dist"),     // filename: 输出文件名     filename: "main.js",   },   // 加载器   module: {     rules: [],   },   // 插件   plugins: [],   // 模式   mode: "development", // 开发模式 }; 

在上面基本使用那一栏里,由于没有配置文件,运行webpack的时候通常会带上后缀:npx webpack /path/to/main.js --mode=development,用于指定入口文件、模式等信息。

添加配置文件之后,webpack会自动读取webpack.config.js这个文件里的配置信息,因此可以直接运行:npx webpack

开发模式介绍

通常会创建两个配置文件,一个对应开发模式,另一个对应生产模式。

开发模式的webpack主要需要完成以下任务:

  1. 编译代码,使浏览器能识别运行

    webpack只能处理js文件,而其它文件,例如:css文件、字体图标、图片资源、html资源等,webpack需要通过配置loader才能处理这些资源;

  2. 代码质量检查

    使用例如eslint之类的代码检查工具,提前发现代码缺陷,也可以检查代码书写是否规范,统一团队编码风格。

处理样式资源

需要使用css-loaderstyle-loader才能处理css文件。

  • css-loader:负责将CSS文件编译成webpack可以识别的模块。
  • style-loader:会动态地创建一个style标签,用于放置webpack 中的css模块。

先安装:

npm i css-loader style-loader -D 

配置webpack:

const path = require("path");  module.exports = {   entry: "./src/main.js",   output: {     path: path.resolve(__dirname, "dist"),     filename: "main.js",   },   module: {     rules: [       {         // 用来匹配 .css 结尾的文件         test: /.css$/,         // use 数组里面 Loader 执行顺序是从右到左         use: ["style-loader", "css-loader"],       },     ],   },   plugins: [],   mode: "development", }; 

这里需要注意的是:use字段指定需要应用的loader,顺序是从右到左的,即css文件先经由css-loader变成webpack可以识别的模块,然后再由style-loader将这些模块注入到html里。

这里提供案例的相关代码:

Webpack5 基础使用笔记

  • /src/assets/css/style.css
#app{     text-align: center;     font-weight: bold; } 
  • /src/js/show.js
export function show(dom, msg){ 	dom.innerText = msg; } 
  • /src/main.js
import {show} from './js/show' import './assets/css/style.css'  const app = document.getElementById('app'); show(app, 'Hello Webpack'); 
  • /public/index.html
<!DOCTYPE html> <html lang="en"> <head>     <title>webpack-learning</title> </head> <body>     <div id="app"></div>     <script src="../dist/main.js"></script> </body> </html> 

同时,可以在package.json中设置常用的指令:

{     ...     "script":{       	"start": "webpack --config webpack.config.js"       },     ... } 

然后,只需要在终端运行:

npm run start 

就会以webpack.config.js为配置,运行webpack,将main.js及其依赖文件,打包到/dist/main.js

此时,打开/public/index.html,可以看到依赖的js文件show函数的功能正常,且引入的style.css样式也被打包并注入到style标签中:

Webpack5 基础使用笔记

Webpack5 基础使用笔记

常用的样式资源还有Less,Sass等,这里再介绍Less样式表的处理,其它样式资源的处理方式是类似的。

首先安装相应的loader:

npm i -D less-loader 

配置webpack:在webpack.config.js文件原有的基础上进行修改。

... module.exports = {     ...     module: {         rules: [             ...             {                 // 用来匹配 .less 结尾的文件                 test: /.less$/,                 use: ['style-loader', 'css-loader', 'less-loader']             }         ]     },     ... } 

上述代码中的...表示原有的,但是这里为了突出重点而省略的代码片段。

配置less-loader只需要在rules数组中添加新的一项,注意use的顺序是从右到左,先把less代码转换成css代码,然后依此类推。

这里我只是在上述css的代码中做了一些修改:

  1. 新增/src/assets/less/style.less文件
#app{     text-align: center;     font-weight: bold; } 
  1. /src/main.js中不引入css文件,而是引入less文件
import {show} from './js/show' import './assets/less/style.less'  const app = document.getElementById('app'); show(app, 'Hello Webpack'); 
  1. 执行npm run start

  2. 打开/pubcli/index.html,可以观察到less也能被正确地处理并注入到最终的style标签中。

Webpack5 基础使用笔记

Webpack5 基础使用笔记

这里再浅浅地提一嘴关于Sass/Scss的样式资源处理配置,他们的loader都是使用sass-loader,因此,在配置test的时候,正则表达式可以使用:/.s[ac]ss$/去同时匹配这两种文件后缀。

处理图片资源

过去的Webpack4 ,处理图片资源需要使用file-loaderurl-loader

现在Webpack5已经将两个Loader功能内置到Webpack里了,只需要简单配置即可处理图片资源。

  • webpack.config.js
... module.exports = {   ...   module: {     rules: [       ...       {         test: /.(png|jpe?g|gif|webp)$/,         type: "asset",       },     ],   },   ... }; 

相关代码:

  1. 在代码中引入图片(记得需要出现在入口文件的依赖中,否则不会被webpack处理)
body{     background-image: url('../images/normal.png'); } #app{     text-align: center;     font-weight: bold;     background-image: url('../images/small.png'); } 

图片可以随便照几张测试,这里我习惯性地将图片放在/src/assets/images目录下。

  1. 运行webpack之后,可以发现图片也被输出了。

Webpack5 基础使用笔记

上面样式资源打包后没有相应的样式资源出现是因为:经过style-loader的处理,样式资源被打包进了/dist/main.js

对图片资源进行优化:将小于某个大小的图片转换成Base64格式。

... module.exports = {   ...   module: {     rules: [       ...       {         test: /.(png|jpe?g|gif|webp)$/,         type: "asset",         parser: {             dataUrlCondition: {                 maxSize: 10 * 1024 // 小于10kb的图片会被base64处理             }         }       },     ],   },   ... }; 

这里我用于测试的两张图片:normal.png和small.png,其中normal.png大于10kb,而small.png小于10kb。

再次打包并运行:

Webpack5 基础使用笔记

可以看到小于10kb的图片文件被转换成Base64格式。

  • 优点:减少请求数量
  • 缺点:main.js体积变得更大

修改输出资源的名称和路径

module.exports = {   ...   output: {     path: path.resolve(__dirname, "dist"),     filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中   },   module: {     rules: [       ...       {         test: /.(png|jpe?g|gif|webp)$/,         type: "asset",         parser: {           dataUrlCondition: {             maxSize: 10 * 1024, // 小于10kb的图片会被base64处理           },         },         generator: {           // 将图片文件输出到 static/imgs 目录中           // 将图片文件命名 [hash:8][ext][query]           // [hash:8]: hash值取8位           // [ext]: 使用之前的文件扩展名           // [query]: 添加之前的query参数           filename: "static/imgs/[hash:8][ext][query]",         },       },     ],   },   ... }; 

上述配置在原来的基础上,修改了:

  • main.js的输出目录;
  • 图片文件的输出目录以及名称。

修改了main.js的输出路径之后,需要修改/public/index.html中的<script>标签的路径。

<script src="../dist/static/js/main.js"></script> 

自动清空上次打包的资源

如果想要每次打包自动覆盖上一次打包生成的资源,使用clean: true

module.exports = {   entry: "./src/main.js",   output: {     path: path.resolve(__dirname, "dist"),     filename: "static/js/main.js",     clean: true, // 自动将上次打包目录资源清空   },   module: {     rules: [       ...     ],   },   ... }; 

处理字体图标资源

字体图标可以到阿里巴巴矢量图标库下载。

下载到本地后解压并添加到项目中的文件夹,这里只需要以下文件:

  • src/fonts/iconfont.ttf
  • src/fonts/iconfont.woff
  • src/fonts/iconfont.woff2
  • src/css/iconfont.css

将文件分开放置需要修改iconfont.css中对于字体文件的引用路径:

@font-face {   font-family: "iconfont"; /* Project id 4000108 */   src: url('../fonts/iconfont.woff2?t=1695445577878') format('woff2'),        url('../fonts/iconfont.woff?t=1695445577878') format('woff'),        url('../fonts/iconfont.ttf?t=1695445577878') format('truetype'); } 

然后在/public/index.html中使用字体图标:

<div id="app"></div> <i class="iconfont icon-wode3"></i> <i class="iconfont icon-search"></i> <i class="iconfont icon-rollback"></i> <script src="../dist/static/js/main.js"></script> 

配置webpack:

... module.exports = {   ...   module: {     rules: [       ...       {         test: /.(ttf|woff2?)$/,         type: "asset/resource",         generator: {           filename: "static/media/[hash:8][ext][query]",         },       },     ],   },   ... }; 

type: "asset/resource"type: "asset"的区别:

  1. type: "asset/resource" 相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理;
  2. type: "asset" 相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式。

处理音频视频资源

音频和视频资源和字体图标做同样的处理,使用type: "asset/resource"

... module.exports = {   ...   module: {     rules: [       ...       {         test: /.(ttf|woff2?|map4|map3|avi)$/,         type: "asset/resource",         generator: {           filename: "static/media/[hash:8][ext][query]",         },       },     ],   },   ... }; 

处理JS资源

webpack只能编译JS中的ES模块化语法,其它更高级的功能需要配置才能使用。

常用的工具有BabelEslint

  • Babel用于将高版本的JS语法转换成ES5语法,是针对兼容性的;
  • Eslint用于检查代码格式。

Eslint

Eslint可以用来检测JS和jsx语法。

使用Eslint需要写配置文件,标注各种rules,用于声明哪些代码规则需要检查。

在安装Eslint之前,先了解一下配置的写法:

  • 新建配置文件.eslintrc.*:位于项目根目录
    • .eslintrc
    • .eslintrc.js
    • .eslintrc.json
    • 上面三种文件命名的区别在于文件类型不同,配置的格式不一样。
  • 直接在package.json中的eslintConfig进行配置。

基本配置

module.exports = {   // 解析选项   parserOptions: {},   // 具体检查规则   rules: {},   // 继承其他规则   extends: [], }; 
  1. parserOptions:解析选项

    parserOptions: {   ecmaVersion: 6, // ES 语法版本   sourceType: "module", // ES 模块化   ecmaFeatures: { // ES 其他特性     jsx: true // 如果是 React 项目,就需要开启 jsx 语法   } } 
  2. rules具体规则

    • off0:关闭
    • warn1:警告
    • error2:报错
    rules: {   semi: "error", // 禁止使用分号   'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告   'default-case': [     'warn', // 要求 switch 语句中有 default 分支,否则警告     { commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了   ],   eqeqeq: [     'warn', // 强制使用 === 和 !==,否则警告     'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告   ], } 
  3. extends继承

    直接引入已有的规则,常见的规则:

    • Eslint官方的规则:eslint:recommended
    • Vue-cli官方的规则:plugin:vue/essential
    • React-cli官方的规则:react-app

    如果本地的rules和继承的规则出现相同的选项,则本地的规则覆盖继承的规则。

安装Eslint

npm i -D eslint-webpack-plugin eslint 

定义配置文件.eslintrc.js

module.exports = {   // 继承 Eslint 规则   extends: ["eslint:recommended"],   env: {     node: true, // 启用node中全局变量     browser: true, // 启用浏览器中全局变量   },   parserOptions: {     ecmaVersion: 6,     sourceType: "module",   },   rules: {     "no-var": 2, // 不能使用 var 定义变量   }, }; 

配置webpack

... const ESLintWebpackPlugin = require("eslint-webpack-plugin");  module.exports = {   ...   plugins: [     new ESLintWebpackPlugin({       // 指定检查文件的根目录       context: path.resolve(__dirname, "src"),     }),   ],   ... }; 

Babel

Babel的配置文件可以是下面的文件名之一:

  • babel.config.js
  • babel.config.json
  • .babelrc
  • .babelrc.js
  • .babelrc.json

或者可以直接在package.json里的babel项进行配置。

babel.config.js为例,基础配置为:

module.exports = {   // 预设   presets: [], }; 

预设可以理解为是Babel插件,扩展Babel的功能。

  • @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript;
  • @babel/preset-react:一个用来编译 React jsx 语法的预设;
  • @babel/preset-typescript:一个用来编译 TypeScript 语法的预设。

安装

npm i babel-loader @babel/core @babel/preset-env -D 

定义配置文件babel.config.js

module.exports = {   presets: ["@babel/preset-env"], }; 

webpack配置

... module.exports = {   ...   module: {     rules: [       ...       {         test: /.js$/,         exclude: /node_modules/, // 排除node_modules代码不编译         loader: "babel-loader",       },     ],   },   ... }; 

处理Html资源

之前没有处理html文件,所做的只是处理JS文件和其它资源,然后手动打开public/index.html。(/public/index.html需要手动引入打包后的dist/static/js/main.js文件)

安装

npm i html-webpack-plugin -D 

配置

... const HtmlWebpackPlugin = require("html-webpack-plugin");  module.exports = {   ...   plugins: [     ...     new HtmlWebpackPlugin({       // 以 public/index.html 为模板创建文件       // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源       template: path.resolve(__dirname, "public/index.html"),     }),   ],   ... }; 

修改/public/index.html

我们的目标是使用html-webpack-plugin完成html文件的打包,现在/public/index.html不需要手动引入dist/static/js/main.js文件了,插件会自动完成这个任务,并把html文件也一并打包到/dist文件夹中。

打包并检查结果

npm run start 

可以看到index.html也被打包了:

Webpack5 基础使用笔记

以下打包之后的/dist/index.html,可以看到被自动添加了<script>标签:

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>webpack-learning</title> <script defer src="static/js/main.js"></script></head> <body>     <div id="app"></div>     <i class="iconfont icon-wode3"></i>     <i class="iconfont icon-search"></i>     <i class="iconfont icon-rollback"></i> </body> </html> 

开发服务器与自动化

使用自动化代替原先的手动输入打包指令的操作。

安装依赖

npm i webpack-dev-server -D 

配置:(webpack.config.js文件)

... module.exports = {   ...   // 开发服务器   devServer: {     host: "localhost", // 启动服务器域名     port: "3000", // 启动服务器端口号     open: true, // 是否自动打开浏览器   },   ... }; 

修改package.json脚本

"scripts": {     "start": "webpack --config webpack.config.js",     "dev": "webpack serve --config webpack.config.js" }, 

新加一个dev指令,用于启动本地服务。

运行指令

npm run dev 

启动服务之后,会自动打开浏览器(可能会被电脑的安全软件拦截,点击允许就行)。

默认启动热加载功能,此时修改源代码,会自动更新。

:使用开发服务器的时候,代码不会被打包到/dist文件夹,而是编译打包在内存中。

生产模式介绍

开发完成代码之后,需要将代码打包给后端用于部署。

打包的配置需要考虑优化问题,主要从两个方面考虑:

  1. 优化代码运行性能
  2. 优化代码打包速度

通常会使用两个配置文件来对应开发模式和生产模式,方便随时切换。

在项目根目录下创建文件夹:config

然后新建两个配置文件:

  • 开发模式配置文件:/config/webpack.dev.js
  • 生产模式配置文件:/config/webpack.prod.js

在上文已经写好的webpack.config.js文件的基础上,稍作修改,拆分出两个模式的配置文件。

配置文件迁移的时候,由于目录变更,配置文件中的路径字符串需要做出相应的修改。同时,mode字段需要区分developmentproduction

开发模式需要注意

  • 没有输出,不需要指定输出路径,也不需要清空输出结果。
  • 需要启动开发服务器。

生产模式需要注意

  • 需要指定输出路径。
  • 关闭开发服务器。

更新package.json里的脚本

"scripts": {     "start": "npm run dev",     "dev": "webpack serve --config ./config/webpack.dev.js",     "build": "webpack --config ./config/webpack.prod.js" }, 
  • 启动开发模式使用:npm run startnpm run dev
  • 启动生产模式使用:npm run build

CSS处理

将css打包成单独文件

上文中的CSS处理是使用style-loader,这样做的结果是:样式会被打包到js文件中,最终再由js生成style标签。

这样做可能会导致白屏现象,因为目前流行的前端框架vue和react主要做的都是单页面应用,需要加载一个很大的js文件来渲染页面,如果样式也由js文件来负责的话,在js解析加载完成之前,页面内容一片空白。这样的页面用户体验不好。

因此,更好的解决方案是将CSS打包成单独的.css文件,然后使用<link>引入。

安装相关的插件

npm i -D mini-css-extract-plugin 

配置webpack.build.js

... // 引入插件 const MiniCssExtractPlugin = require("mini-css-extract-plugin");  module.exports = {   ...   module: {     // css相关的rules,将style-loader替换成新插件的loader     rules: [       {           // 用来匹配 .css 结尾的文件           test: /.css$/,           use: [MiniCssExtractPlugin.loader, 'css-loader']       },         {             // 用来匹配 .less 结尾的文件             test: /.less$/,             use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']         },       ...     ],   },   plugins: [     ...     // 提取css成单独文件     new MiniCssExtractPlugin({       // 定义输出文件名和目录       filename: "static/css/main.css",     }),   ],   mode: "production", }; 

主要步骤:

  1. 引入插件;
  2. 修改rules中的loader;
  3. 新增plugins,并指定输出的文件名。

运行打包指令

npm run build 

效果:

  1. 输出了/dist/static/css/main.css文件:

    Webpack5 基础使用笔记

  2. 输出的/dist/index.html中出现了<link>标签,并引入了打包后的css文件。

css兼容性处理

css兼容性处理可以使用postcss,拥有许多插件,可以按需配置,可以与解决JS兼容性问题的Babel进行类比。

安装

需要安装:

  • postcss:postcss本身
  • postcss-loader:为了webpack接入的loader
  • postcss-preset-env:postcss官方提供的预设配置
npm i -D postcss postcss-loader postcss-preset-env 

配置webpack.prod.js

只需要在css-loader之前新增一个postcss-loader就可以:

rules: [     {         // 用来匹配 .css 结尾的文件         test: /.css$/,         use: [             MiniCssExtractPlugin.loader,              'css-loader',             // 在css-loader之前使用postcss-loader             {                 loader: 'postcss-loader',                 options: {                     postcssOptions: {                         plugins: ['postcss-preset-env']                     }                 }             }         ]     },     {         // 用来匹配 .less 结尾的文件         test: /.less$/,         use: [             MiniCssExtractPlugin.loader,             'css-loader',              {                 loader: 'postcss-loader',                 options: {                     postcssOptions: {                         plugins: ['postcss-preset-env']                     }                 }             },             'less-loader',         ]     }, ] 

对于其它css扩展语法,例如less,可以先使用less-loader转成css,然后使用postcss-loader处理其兼容性,最后才是使用css-loader处理成webpack可以处理的模块,以及打包用的MiniCssExtractPlugin.loader

兼容性控制

package.json文件中可以写入browserslist这个属性,指定兼容性的考虑程度。

这个属性是共用的,与兼容性问题相关的许多插件都会自动读取这个属性。

常用案例:

{     "browserslist": ["last 2 version", "> 1%", "not dead"] } 

css压缩

减少打包后的体积。

安装

npm i -D css-minimizer-webpack-plugin 

配置

... const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  module.exports = {     ...     plugins: [         ...         // css压缩         new CssMinimizerPlugin()     ],     mode: 'production' } 

html和js压缩

生产环境下,html和js是默认压缩的,即打包后的代码都是单行的。

总结

5个核心概念

  1. entry(入口):webpack从这个文件开始进行打包,并打包其依赖文件;
  2. output(输出):决定了webpack打包后的文件的文件名、地址等;
  3. loader(加载器):webpack只能处理js文件,其它文件比如css文件、图片资源、jsx文件,需要使用loader才能解析;
  4. plugins(插件):扩展webpack的功能,每一个插件如何配置取决于插件的提供者如何设计;
  5. mode(模式):主要有两种模式,开发模式(development)和生产模式(production)。

2种模式

使用两个独立的配置文件。

  • 开发模式:需要代码编译、语法检查、热加载。
  • 生产模式:需要考虑性能与兼容性。

参考资料