奶牛先生 发表于 2023-10-1 21:45:04

Webpack5 基础使用笔记


(概念 | 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的配置有五大核心概念:

[*]entry(入口):webpack从这个文件开始进行打包,并打包其依赖文件;
[*]output(输出):决定了webpack打包后的文件的文件名、地址等;
[*]loader(加载器):webpack只能处理js文件,其它文件比如css文件、图片资源、jsx文件,需要使用loader才能解析;
[*]plugins(插件):扩展webpack的功能,每一个插件如何配置取决于插件的提供者如何设计;
[*]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主要需要完成以下任务:

[*]编译代码,使浏览器能识别运行
webpack只能处理js文件,而其它文件,例如:css文件、字体图标、图片资源、html资源等,webpack需要通过配置loader才能处理这些资源;
[*]代码质量检查
使用例如eslint之类的代码检查工具,提前发现代码缺陷,也可以检查代码书写是否规范,统一团队编码风格。
处理样式资源

需要使用css-loader和style-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里。
这里提供案例的相关代码:


[*]/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>
   
   
</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标签中:

常用的样式资源还有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的代码中做了一些修改:

[*]新增/src/assets/less/style.less文件
#app{
    text-align: center;
    font-weight: bold;
}
[*]/src/main.js中不引入css文件,而是引入less文件
import {show} from './js/show'
import './assets/less/style.less'

const app = document.getElementById('app');
show(app, 'Hello Webpack');
[*]执行npm run start
[*]打开/pubcli/index.html,可以观察到less也能被正确地处理并注入到最终的style标签中。

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

过去的Webpack4 ,处理图片资源需要使用file-loader和url-loader。
现在Webpack5已经将两个Loader功能内置到Webpack里了,只需要简单配置即可处理图片资源。

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

[*]在代码中引入图片(记得需要出现在入口文件的依赖中,否则不会被webpack处理)
body{
    background-image: url('../images/normal.png');
}
#app{
    text-align: center;
    font-weight: bold;
    background-image: url('../images/small.png');
}图片可以随便照几张测试,这里我习惯性地将图片放在/src/assets/images目录下。

[*]运行webpack之后,可以发现图片也被输出了。

上面样式资源打包后没有相应的样式资源出现是因为:经过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。
再次打包并运行:

可以看到小于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位
          // : 使用之前的文件扩展名
          // : 添加之前的query参数
          filename: "static/imgs/",
      },
      },
    ],
},
...
};上述配置在原来的基础上,修改了:

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

修改了main.js的输出路径之后,需要修改/public/index.html中的自动清空上次打包的资源

如果想要每次打包自动覆盖上一次打包生成的资源,使用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中使用字体图标:
配置webpack:
...
module.exports = {
...
module: {
    rules: [
      ...
      {
      test: /\.(ttf|woff2?)$/,
      type: "asset/resource",
      generator: {
          filename: "static/media/",
      },
      },
    ],
},
...
};type: "asset/resource"和type: "asset"的区别:

[*]type: "asset/resource" 相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理;
[*]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/",
      },
      },
    ],
},
...
};处理JS资源

webpack只能编译JS中的ES模块化语法,其它更高级的功能需要配置才能使用。
常用的工具有Babel和Eslint:

[*]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: [],
};
[*]parserOptions:解析选项
parserOptions: {
ecmaVersion: 6, // ES 语法版本
sourceType: "module", // ES 模块化
ecmaFeatures: { // ES 其他特性
    jsx: true // 如果是 React 项目,就需要开启 jsx 语法
}
}
[*]rules具体规则

[*]off或0:关闭
[*]warn或1:警告
[*]error或2:报错
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 除了少数情况下不会有警告
],
}
[*]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也被打包了:


以下打包之后的/dist/index.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文件夹,而是编译打包在内存中。
生产模式介绍

开发完成代码之后,需要将代码打包给后端用于部署。
打包的配置需要考虑优化问题,主要从两个方面考虑:

[*]优化代码运行性能
[*]优化代码打包速度
注:
通常会使用两个配置文件来对应开发模式和生产模式,方便随时切换。
在项目根目录下创建文件夹:config。
然后新建两个配置文件:

[*]开发模式配置文件:/config/webpack.dev.js
[*]生产模式配置文件:/config/webpack.prod.js
在上文已经写好的webpack.config.js文件的基础上,稍作修改,拆分出两个模式的配置文件。
配置文件迁移的时候,由于目录变更,配置文件中的路径字符串需要做出相应的修改。同时,mode字段需要区分development或production。
开发模式需要注意:

[*]没有输出,不需要指定输出路径,也不需要清空输出结果。
[*]需要启动开发服务器。
生产模式需要注意:

[*]需要指定输出路径。
[*]关闭开发服务器。
更新package.json里的脚本
"scripts": {
    "start": "npm run dev",
    "dev": "webpack serve --config ./config/webpack.dev.js",
    "build": "webpack --config ./config/webpack.prod.js"
},

[*]启动开发模式使用:npm run start或npm run dev
[*]启动生产模式使用:npm run build
CSS处理

将css打包成单独文件

上文中的CSS处理是使用style-loader,这样做的结果是:样式会被打包到js文件中,最终再由js生成style标签。
这样做可能会导致白屏现象,因为目前流行的前端框架vue和react主要做的都是单页面应用,需要加载一个很大的js文件来渲染页面,如果样式也由js文件来负责的话,在js解析加载完成之前,页面内容一片空白。这样的页面用户体验不好。
因此,更好的解决方案是将CSS打包成单独的.css文件,然后使用引入。
安装相关的插件
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:
      },
      {
            // 用来匹配 .less 结尾的文件
            test: /\.less$/,
            use:
      },
      ...
    ],
},
plugins: [
    ...
    // 提取css成单独文件
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/main.css",
    }),
],
mode: "production",
};主要步骤:

[*]引入插件;
[*]修改rules中的loader;
[*]新增plugins,并指定输出的文件名。
运行打包指令
npm run build效果:

[*]输出了/dist/static/css/main.css文件:

[*]输出的/dist/index.html中出现了标签,并引入了打包后的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个核心概念:

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

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


[*]尚硅谷 Web 前端之 Webpack5 教程

来源:https://www.cnblogs.com/feixianxing/p/webpack-5-basic-usage.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Webpack5 基础使用笔记