webpack从入门到放弃
更新中!
更新中!
更新中!
概念及安装
概念
webpack
是一个静态的模块化打包工具,为现代的 JavaScript
应用程序。
它有四个核心概念:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugins)
安装
由于 webpack
依赖 Node
环境,所以在安装 webpack
之前需要先安装 Node!
webpack
的安装分为两个:webpack
、webpack-cli
。
1 | npm i webpack webpack-cli -g // 全局安装 |
如果使用全局安装,直接在终端使用 webpack
即可。
如果使用局部安装,可以使用如下两种方法进行打包:
使用
npx
命令:1
npx webpack
在
package.json
文件的scripts
中添加:1
"build": "webpack"
然后在终端运行 npm run build
即可。
基本使用
下面我们就来简单的使用下。
首先按照如下命令创建文件夹及文件:
1 | mkdir demo1 |
在 index.html
文件中引入 src/index.js
文件:
1 | <script src="./src/index.js" type="module"></script> |
分别编辑另外三个 .js
文件:
1 | // index.js |
1 | // date.js |
1 | // math.js |
当我们在浏览器中打开 index.html
文件后,会发现有如下错误:
1 | Uncaught ReferenceError: require is not defined |
这时候就需要使用 webpage 了。
如果全局安装了 webpack
,可以直接在该 demo1
文件夹下使用该命令:
1 | webpack |
当执行完成后,会发现根目录下多了一个 dist/main.js
文件。
这时候记住需要把 index.html
的引入做如下修改:
1 | <script src="./dist/main.js"></script> |
最后打开浏览器就正常打印输出了。这时我们就完成了 webpack
的基本使用啦!
当我们执行 webpack
后,webpack
会将 src/index.js
文件作为入口文件,并将其打包到 dist
文件夹下。如果在 src
目录下没有 index.js
文件,将会报错。
webpack.config.js
入口和出口
当我们使用 webpack
命令时,可以指定入口文件和出口文件,例如:
1 | npx webpack --entry ./src/main.js --output-path ./build |
但是这样操作就显得十分繁琐。因此,我们可以在 webpack.config.js
配置文件中进行配置。
首先在根目录下新建 webpack.config.js
文件并编辑:
1 | const path = require('path') |
配置完成后,我们可以直接在终端使用 npm run build
即可。
指定配置文件
假设当根目录下 webpack.config.js
文件的文件名不是它,而是其他的文件名,比如 webpack.demo.config.js
。
这时候执行 npm run build
将会报错,这时我们需要利用 config
来配置下文件名。
编辑 package.json
文件,并修改 scripts
的内容:
1 | "build": "webpack --config webpack.demo.config.js" |
这样后,执行 npm run build
将正常打包了。
mode
mode
默认值是 production
。
production
:会让打包后的文件压缩、丑化;development
:不会压缩、丑化;none
:不使用任何默认优化选项。
loaders
css-loader
现在我们来引入一下 css
文件。
首先在 src
目录下新建 css/index.css
文件,并添加内容:
1 | .content { |
然后再在 js
文件夹中新建 component.js
文件:
1 | import "../css/index.css" |
并在 main.js
文件中引入:
1 | import './js/component' |
当我们执行 npm run build
时,会报错,因为此时无法处理 css
文件,缺少 loader。
下面我们就来安装一下 css-loader
:
1 | npm i css-loader -D |
安装完成后,css-loader
有如下三种使用方法:
- 内联
- cli(在webpack5中移除此方案)
- 配置
下面来依次讲解:
- 内联
修改component.js
文件:1
import "css-loader!../css/index.css"
如果需要使用多个 loader
,可以使用 !
来分开。例如:import "css-loader!css-loader!../css/index.css"
cli
由于在webpack5
中使用此方法无效了,所以这里就不做介绍了。配置(推荐)
编辑 webpack.config.js
文件:
1 | module.exports = { |
当配置完成后,运行 npm run build
后,我们发现 css
还是没有生效,这是因为 css-loader
只是负责将 .css
文件进行解析,并不会将解析后的 css
插入到页面中。如果希望完成插入的操作,此时还需要使用到 style-loader
。
style-loader
安装:
1 | npm i style-loader -D |
编辑 webpack.config.js
文件:
1 | module.exports = { |
注意:webpack 在编译 loader 的时候是从下往上或者说是从右往左编译的,因此需要先使用的 loader 应该放在最后。
然后重新运行 npm run build
后就可以看到效果了。
sass-loader
安装:
1 | npm i sass-loader sass -D |
在 css
文件夹下新建 component.scss
:
1 | $backgroundColor: blue; |
在 component.js
中引入:
1 | import "../css/component.scss" |
编辑 webpack.config.js
文件:
1 | module.exports = { |
然后重新运行 npm run build
后就可以看到效果了。
使用 less-loader 也是同理。
postcss-loader
在讲解 postcss-loader
之前,我们先来了解下其他预备知识。
浏览器兼容性
针对不同浏览器支持的特性,比如:css 特性、 js 语法之间的兼容性,我们应该如何去处理呢?
一般现在都可以使用 autoprefixer 、babel 这些解决方案。
browserslist
我们在使用脚手架开发项目的时候,有时候会看到类似这样的配置信息:
1 | > 1% |
那这些配置信息是什么意思呢?
其实,这些都是告诉工具我现在需要适配哪些浏览器。比如:> 1%
是告诉工具要兼容市场占有率大于 1%
的浏览器。
我们可以在 caniuse 上查询浏览器的市场占有率。
使用 browserslist 可以在不同的前端工具之间,共享目标浏览器和 Node.js 版本的配置。
它有两种配置方法:
直接在
package.json
中添加:1
2
3
4
5
6
7{
"browserslist":[
"> 1%",
"last 2 versions",
"not dead"
]
}在根目录新建
.browserslistrc
文件:1
2
3> 1%
last 2 versions
not dead
PostCSS工具
PostCSS
是一个通过 JavaScript
来转换样式的工具。它可以帮我们进行一些 CSS
的转换和适配,比如:自动添加浏览器前缀、css 样式的重置。
Autoprefixer 可以用来测试哪些样式浏览器需要添加前缀。
命令行
如果我们想要用命令行使用 postcss
,那就需要单独安装一个工具 postcss-cli
。
安装:
1 | npm i postcss -D |
我们在 src/css
下新建 test.css
文件:
1 | .content { |
然后在命令行中执行:
1 | npx postcss -o result.css ./src/css/test.css |
当我们查看 result.css
文件后,发现并没有加前缀,然后再看看控制台有如下输出:
1 | You did not set any plugins, parser, or stringifier. Right now, PostCSS does nothing. Pick plugins for your case on https://www.postcss.parts/ and use them in postcss.config.js. |
这时候我们需要安装一下 autoprefixer
插件:
1 | npm i autoprefixer -D |
然后再执行:
1 | npx postcss --use autoprefixer -o result.css ./src/css/test.css |
就会发现 result.css
文件加了前缀了:
1 | .content { |
我们发现使用命令行来添加浏览器前缀就过于繁琐,因此在项目中就需要使用到 postcss-loader
来简化操作。
postcss-loader
安装:
1 | npm i postcss-loader -D |
编辑 webpack.config.js
文件,添加 postcss-loader
配置信息:
1 | module.exports = { |
postcss-preset-env
在我们配置 postcss-loader
时,配置插件并不需要使用 autoprefixer
。我们可以使用另外一个插件 postcss-preset-env
。
它可以帮助我们将现代的 CSS
特性转换成大多数浏览器认识的 CSS
,并会根据目标浏览器或运行时环境添加所需要的 polyfill
。并且它已经内置了 autoprefixer
。
我们来修改下 src/css/index.css
文件:
1 | .content { |
我们将 color
颜色设置成 8
位,其中后两位代表透明度,但这种写法在部分浏览器上是不兼容不识别的。
我们执行 npm run build
后在浏览器看看效果。
我们会发现在 Chrome
浏览器上是生效的,打开控制台后发现 CSS
样式中 color
还是这种写法:color: #12345678;
,这不是我们所想要的。
所以我们在开发时,需要将这类特性转换成大多数浏览器可以识别的格式。
autoprefixer
这个插件只会加一些浏览器前缀,这时候需要用到 postcss-preset-env
插件了。
安装 postcss-preset-env
:
1 | npm i postcss-preset-env -D |
编辑 webpack.config.js
文件:
1 | module.exports = { |
由于 postcss-preset-env
中内置了 autoprefixer
特性,因此可以将 autoprefixer
配置删除掉。
在配置文件中 require("postcss-preset-env")
可以简写成:"postcss-preset-env"
。
执行 npm run build
后在浏览器打开控制台找到相应的样式,就会发现将 color
转换成了 color: rgba(18,52,86,0.47059);
。
postcss.config.js
在配置文件中 postcss-preset-env
也需要作用于 sass
,因此在 sass
也需要做相同的配置:
1 | module.exports = { |
但是这样写,就比较重复了,这时候我们需要将配置信息进行抽离:
1 | module.exports = { |
然后在根目录新建 postcss.config.js
文件:
1 | module.exports = { |
注意
目前 src/css
目录下有 index.css
、test.css
、component.scss
三个文件,现将前两个文件修改如下:
1 | /* index.css */ |
1 | /* test.css */ |
现在我们直接运行 npm run build
后,打开浏览器发现并没有添加浏览器前缀和转换。
因为在 webpack.config.js
中,我们 loader
是这样写的:"style-loader","css-loader","postcss-loader"
。
这样写的话,loader
是这样执行的:首先 js/component.js
文件引入了 index.css
文件,然后 postcss-loader
处理该 css
文件,但是它不能处理 @import './test.css';
。然后执行 css-loader
,它会处理 @import './test.css';
语法并处理 test.css
文件,这样就导致了 test.css
文件没有被 postcss-loader
处理。
因此,需要配置 css-loader
:
1 | module.exports = { |
为 "css-loader"
配置 options
,并设置 importLoaders
,具体可以参考 css-loader - options - importloaders。
file-loader
首先我们在 src
目录下新建 img
文件夹并放 2 张图片进去。
编辑 component.js
文件:
1 | import "../css/index.css" |
编辑 index.css
文件:
1 | @import './test.css'; |
然后执行 npm run build
后,会发现控制台报错,因为缺少 loader
来处理图片文件。
这时候需要用到 file-loader ,它可以帮助我们处理 import / require()
方式引入的一个文件资源,并会将它们放到输出文件夹中。
下面我们就来安装使用 file-loader
:
1 | npm i file-loader -D |
编辑 webpack.config.js
文件:
1 | module.exports = { |
当我们执行 npm run build
后,会发现 img
标签的图片加载不出来:<img src="[object Module]">
。
这是因为 file-loader
在 5.x
后的版本,如果要用 require
来拿到资源,就需要使用 default
。
现在修改下 component.js
文件:
1 | imgELemenet.src = require("../img/1.png").default |
现在打包运行后就可以看到图片了。
我们还可以使用 import
来加载资源:
1 | import imgUrl from "../img/1.png"; |
在 build
打包后的文件夹中我们发现图片的文件名类似于这样:04d1c0acbb4faf7384266ffbd9992a09.png
,它采用了 MD4
的算法,该算法根据文件内容生成打包后的文件名的。
但是如果图片多了,我们就不知道 src/img
与 build
的图片文件的对应关系。
我们想要把打包前的文件名加到打包后的文件名前面,要想达到这样的效果就要对生成的文件进行重命名,下面就来配置一下 webpack.config.js
文件:
1 | module.exports = { |
在 webpack5
中一般不使用此 loader
。
url-loader
它可以将较小的文件转成 base64 的 url。
安装:
1 | npm i url-loader -D |
编辑 webpack.config.js
文件:
1 | module.exports = { |
url-loader
用法与 file-loader
用法一致,只需要将 file-loader
改为 url-loader
即可。
在开发中,我们希望把小的图片转换成 base64
,这样可以和页面一起被请求,减少不必要的请求。而大的图片如果也进行了转换,反而会影响页面的请求速度。
因此,添加 limit
参数就可以解决:
1 | module.exports = { |
limit
设置为 100 * 1024
表示:小于 100KB
的文件将转换为 base64
.
在 webpack5
中一般不使用此 loader
。
asset module type
在使用 webpack5
版本之前,加载资源需要使用到 raw-loader
、file-loader
、url-loader
。但是从 webpack5
开始,可以直接使用资源模块类型(asset module type)来替代那些 loader。
资源模块类型(asset module type)通过添加 4
种新的模块类型:
- asset/resource:发送一个单独的文件并导出
url
,替换file-**loader
; - asset/inline:导出一个资源的
data url
,替换url-loader
; - asset/source:导出资源的源代码,替换
raw-loader
; - asset:在导出一个
data url
和发送一个单独的文件之间自动选择。
下面我们就来分别使用下。
asset/resource
图片资源文件
编辑 webpack.config.js
文件:
1 | const path = require('path') |
我们可以在 output
中设置 assetModuleFilename
来指定打包后的资源文件放在哪个文件夹下。这样设置的话所有通过 assetModuleFilename
打包的文件将会都放到那个文件夹下。
除了这种方法,我们还可以使用设置 generator
:
1 | const path = require('path') |
字体图标文件
将 iconfont 下载的图标文件复制到 src/font
文件夹下,然后在 src/css/index.css
中引入:
1 | @import '../font/iconfont.css'; |
编辑 webpack.config.js
文件:
1 | module.exports = { |
像 mp3、mp4
这些文件,也是类似这样的操作。
asset/inline
编辑 webpack.config.js
文件:
1 | module.exports = { |
它的效果跟 url-loader
一样。
asset
编辑 webpack.config.js
文件:
1 | module.exports = { |
plugin
CleanWebpackPlugin
当我们修改配置后,都需要重新打包,而每次手动删除打包文件就很麻烦。这里就可以借助 CleanWebpackPlugin
插件来完成。
安装:
1 | npm i clean-webpack-plugin -D |
配置:
1 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') |
在 webpack5
中可以不使用 clean-webpack-plugin
插件,可以添加 output.clean option。
1 | output: { |
HtmlWebpackPlugin
安装:
1 | npm i html-webpack-plugin -D |
配置:
1 | const HtmlWebpackPlugin = require('html-webpack-plugin') |
我们还可以指定 html
模板:
1 | module.exports = { |
DefinePlugin
DefinePlugin
允许在编译时创建配置的全局常量,是 webpack
内置的一个插件。
使用:
1 | const { DefinePlugin } = require('webpack') |
CopyWebpackPlugin
它可以将指定文件夹的内容复制到打包后的文件夹。
下面我们就来简单使用下,把 public/favicon.ico
文件复制到打包的文件夹中。
安装:
1 | npm i copy-webpack-plugin -D |
配置:
1 | const CopyWebpackPlugin = require('copy-webpack-plugin') |
globOptions
的 ignore
值可以忽略某个文件不被复制过去。
source-map
当我们打包后运行在浏览器上的代码是被压缩、丑化了的。当我们代码报错需要调试时,调试转换后的代码十分困难。因此,需要使用到 source-map
。
它可以从已转换的代码映射到原始的源文件。
使用
可以通过配置 webpack.config.js
文件:
1 | module.exports = { |
在转换后的代码中添加一个注释,指向 sourcemap
:
1 | //# sourceMappingURL=bundle.js.map |
注意:在 Chrome
浏览器中,需要打开 source-map
:
- 打开开发者工具;
- 打开设置;
- 在
Preferences
的Sources
中勾选Enable JavaScript source maps
和Enable CSS source maps
。