Webpack入坑指北
初始化项目
首先新建一个项目然后初始化。
1 |
|
创建一个 src/main.js 文件,随便写点啥
在根目录创建 build/webpack.common.js 文件
1 |
|
这里需要注意一点是为什么 webpack 配置文件要用 cjs 来写 ?
答案就是因为 webpack 打包过程是在 node 环境下
在 package.json 加上打包命令
1 |
|
通过执行 pnpm run build
进行打包,执行后会生成一个 dist
目录,里面就是我们打包的产物。
打包时控制台会报
The 'mode' option has not been set
的警告,意思就是我们需要设置一个 mode 它可以是development
开发模式、production
生产模式、none
无模式。另外如果 shell 命令中参数和配置文件冲突,生效的是 shell 命令参数。
创建 HTML
打包好的产物我们希望能通过html在浏览器中打开看效果,需要通过 html-webpack-plugin
插件实现
1 |
|
在配置文件中写入
1 |
|
plugins 就是我们声明插件来对 webpack 的功能进行扩展的地方。这时候再打包,发现产物目录下有一个 html 文件,并且通过 script 引入了我们打包的 js 文件。
打包时显示进度
1 |
|
这里的 chalk 最新版本(5.3.0)使用 esm 引入,我们使用 4.1.2 版本
使用
1 |
|
再进行打包就能看到进度条了,另外可以通过 chalk 来修改进度条的颜色等。
处理样式
我们定义一个 main.css 文件,在 main.js 引入,进行打包时会发现控制台报错,并提示我们需要用 loader 来处理这个类型的文件。
处理 css 类型文件需要用到以下两个 loader。
1 |
|
在配置文件中声明使用这两个 loader 来处理 css 类型文件。
1 |
|
module 是我们用来定义某种资源通过指定的 loader 来处理,如上代码我们通过 "style-loader"
和 "css-loader"
来处理后缀名为 css
的文件,"css-loader"
做的是解析 css 文件,翻译成 JavaScript 代码,使得 webpack 能够如同处理 JS 代码一样解析 CSS,"style-loader""
做的是将解析出来的文件通过 style
标签插入到页面中。
另外 loader 的书写顺序也是有要求的,一般情况下,会按照由右到左,由上到下的顺序执行。所以上面代码才是先解析再插入到页面。
通过打包的产物发现我们的 css 已经被打包进 js 文件中,下面我们把 css 代码抽离出来。安装MiniCssExtractPlugin插件
1 |
|
然后进行配置
1 |
|
这时候再打包可以看到产物中多一个 css 文件,这样我们就把 css 文件抽离出来了
再看产物中的 index.html,多了一行 link 标签,所以这个插件的作用就是把 css 文件抽离并通过 link 标签的形式插入到页面中,这也是为什么在上面的配置中我们去掉了 style-loader。
1 |
|
使用 MiniCssExtractPlugin 插件的好处在于,避免了 js 和 css 只能同步加载,对性能有影响,并且其中任意一个更新都会导致缓存失效。另外该插件必须和上面写到的 HTMLWebpackPlugin 插件一起使用(不然连 html 文件都没有怎么插入到页面)。
预处理器
我们以 less 为例
1 |
|
然后新建一个 less 文件,随便写点样式,在打包入口文件导入,接着进行对 less 的配置
1 |
|
无非在处理 css 文件的基础上,多了一个 less-loader ,这个 loader 做的就是把 less 翻译成 css。
postcss
安装 postcss 和 postcss-loader
1 |
|
自动添加前缀
postcss 有强大的插件生态来处理各种问题,常用的如 autoprefixer,他能根据配置的浏览器兼容性,检测出需要添加前缀的 css 属性,构建的时候进行添加。
1 |
|
对 postcss 配置
1 |
|
在 less 文件中写入
1 |
|
打包后可以看到产物已经增加了前缀
关于系统支持的浏览器可以通过 package.json 的 browserslist 或者
.browserslistrc
文件进行配置
另外postcss-preset-env也可以做同样的事情,甚至更强大,他还能将现代 CSS 转换成大多数浏览器都能理解的东西。
处理 js
webpack 默认是支持处理 js 文件的,但在一些情况下,js 代码会存在兼容性的问题,在低版本的浏览器无法运行的情况,所以我们需要对这部分代码进行处理。这里用到的是 babel
对代码进行转译。
1 |
|
@babel/core:babel核心库
@babel/preset-env 根据目标环境转译 JavaScript 的预设
babel-loader webpack 中的一个 loader,将 babel 集成到 webpack 构建过程中
配置
1 |
|
在入口文件我们声明一个箭头函数并执行,然后分别看使用 babel-loader 进行语法降级和 不使用的效果,可以看到用 babel 后,箭头函数被转译成如下的形式。
1 |
|
处理 ts
使用 ts-loader
1 |
|
配置
1 |
|
还需要创建 ts 的配置文件 tsconfig.json
1 |
|
这时候就可以执行构建了
使用 babel
1 |
|
配置
1 |
|
两者区别
使用 @babel/preset-typescript
只是进行了代码转换,而 ts-loader
还会对代码进行类型检查。例如我们将 number 赋值给一个 string 类型。ts-loader
在构建时会报错。
处理资源
file-loader
安装
1 |
|
file-loader 将资源重命名,在代码中插入 url 地址。
url-loader
安装
1 |
|
配置
1 |
|
url-loader 会对比资源大小和配置的限制大小,如果没超出限制就转为 Base64 编码,超出的话就同 file-loader 一致。
raw-loader
不转译,直接将文件复制到产物。
Webpack5 通过 module.rules.type
指定资源类型。
asset/resource
对标 file-loader
asset
对标 url-loader
,module.rules.parser.dataUrlCondition
用于限定文件大小阈值asset/source
对标 raw-loader
/ asset/inline
区分开发环境和生产环境
我们上面写到的 webpack.common.js 可以作为一个基础的配置,在开发环境和生产环境中配置也是有差异的,所以我们还需要分别去配置。
创建 build/webpack.dev.js
和 build/webpack.prod.js
因为开发环境和生产环境都基于基础配置,我们需要通过 webpack.merge 将他们连接起来。
1 |
|
webpack-dev-server
一般开发环境我们希望项目构建后能直接在浏览器运行,这一点通过 webpack-dev-server
来实现
1 |
|
配置
1 |
|
重写启动命令
1 |
|
执行 pnpm run dev
将会在 3000 端口启动。
关于打包命名
格式 | 描述 |
---|---|
[name] | 文件名称 |
[hash] | 每次webpack构建时生成一个唯一的hash值 |
[chunkhash] | 根据chunk生成hash值,来源于同一个chunk,则hash值就一样 |
[contenthash] | 根据内容生成hash值,文件内容相同hash值就相同 |