一、loader
loader就是一个打包的方案,在打包的过程中,webpack不认识非.js后缀的这些模块,但是loader知道对于某一个特定的文件(如.jpg)该如何打包。那么在配置项中file:loader就会帮助它来打包这些静态文件,同时会在dist文件夹下生成这些文件。
1.1 安装
1 | npm install file-loader -D |
1.2配置
1 | module.export{ |
1.3 option
没有option配置项时打包生成的文件名为哈希值
,加上option时:name:'[name].[ext]'
代表打包出的结果,图片为原本的名字.后缀名
name:'[name]_[hash].[ext]'
代表打包出的结果,图片为原本的名字_哈希值.后缀名
1.4 file-loader
当遇到jpg png gif这样的文件时,用file-loader
打包,输出路径为images,到时候会在dist目录下生成一个images的文件夹。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19module.export{
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules:[
{
test: /\.txt$/,
use: {
loader: 'file-loader',
option: {
name: '[name]_[hash].[ext]'
}
}
}
]
}
}
1.5 url-loader
可以用url-loader
代替file-loader
的功能(安装:npm install url-loader -D),用url-loader打包是可以看到网页内容的,又不需要去找文件路径,少了一次http请求,(但是打包的时候,dist目录下没有图片文件,打开index.html却能看到图片,那是因为打包的时候把图片转成了base64)但是如果图片文件很大,打包生成的bundle.js文件也会相应很大,这样页面加载时候会很慢,那么正确使用url-loader的方式是什么呢?1
2
3
4
5
6
7
8
9
10
11
12
13
14module: {
rules:[
{
test:/\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
option: {
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
}
]
}
1.6 limit
在option里面配置limit,当图片小于10240字节(10KB)时使用url-loader以base64形式打包到js文件里面,当大于10KB时用file-loader打包。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15module: {
rules:[
{
test:/\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
option: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}
]
}
1.7 style-loader、css-loader、sass-loader
打包CSS文件,同样的,webpack不认识css后缀的文件,所以要在webpack.package.js里面去配置。
安装style-loader
和css-loader
:1
npm install style-loader css-loader -D
1 | module.export{ |
如果是sass这种比较新潮的样式文件的话安装sass-loader
和node-loader
1
2
3
4
5
6
7
8{
test: /\.scss$/,
use:[
'style-loader',
'css-loader',
'scss-loader',
]
}
现在我们已经有3个loader了,在webpack的配置里,loader是有先后顺序的,它的执行顺序是:从下到上,从右到左。所以当我们去打包一个scss文件时,首先会执行sass-loader,对代码翻译成css,给到css-loader,处理好后给style-loader挂载到页面上。
1.8 postcss-loader
有时候我们会写transform:translate(100px,100px)这样的样式,一般这样的样式都会有厂商前缀,比如-webkit-,那在加了postcss-loader
之后,就不需要我们手动写了,它会自动把它添加上去。安装:1
npm install postcss-loader -D
postcss要求我们在目录下创建一个postcss.config.js
文件并安装autoprefixer
这样的一个插件:1
npm i autoprefixer -D
1 | { |
📁postcss.config.js1
2
3
4
5module.exports = {
plugins: [
require('autoprefixer')
]
}
1.9 importLoaders
有时候会在scss文件里再引用一个scss文件(简称第二文件),在第一文件处理完后第二文件便直接从css-loader开始,到style-loader,这样的话就跳过postcss-loader和sass-loader了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33module.export{
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules:[
{
test: /\.txt$/,
use: {
loader: 'file-loader',
option: {
name: '[name]_[hash].[ext]'
}
}
},
{
test: /\.css$/,
use:[
'style-loader',
{
loader: 'css-loader',
options:{
importLoaders: 2
}
},
'scss-loader',
'postcss-loader'
]
}
]
}
}
所以要把css-loader写在一个对象里面,并在里面配置importLoaders:2,意思是第二文件也要从postcss-loader和sass-loader开始编译。1
2
3
4
5
6
7
8
9
10
11
12use:[
'style-loader',
{
loader: 'css-loader',
options:{
importLoaders: 2,
modules: true
}
},
'scss-loader',
'postcss-loader'
]
modules: true
开启css的模块化打包,避免全局导入时对样式的影响。
1.10 打包字体
1 | { |
不需要option配置
二、使用plugins插件打包文件更便捷
2.1安装:
1 | npm install html-webpack-plugin -D |
2.2 htmlwebpackplugin
htmlwebpackplugin这个插件会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。
📁webpack.config.js1
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugin可以在webpack运行到某个时刻的时候,帮你做一些事情1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38module.export{
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules:[
{
test: /\.txt$/,
use: {
loader: 'file-loader',
option: {
name: '[name]_[hash].[ext]'
}
}
},
{
test: /\.css$/,
use:[
'style-loader',
{
loader: 'css-loader',
options:{
importLoaders: 2
}
},
'scss-loader',
'postcss-loader'
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
}
2.3 clean-webpack-plugin
有时候我们打包后会留下上次打包在dist里的内容,如果想要覆盖,用clean-webpack-plugin
就可以了,他是第三方插件,在官网上找不到文档。在打包执行之前运行
安装:1
npm install clean-webpack-plugin -D
📁webpack.config.js1
const CleanWebpackPlugin = require('clean-webpack-plugin');
1 | plugins:[ |
三、Entry 与 Output 的基础配置
它会在打包生成的index.html中把main.js和sub.js放进去,是因为之前在打包配置文件里面使用了htmlwebpackplugin1
2
3
4
5
6
7
8
9
10
11module.export{
mode: 'development',
entry: {
main: './src/index.js'
sub: './src/index.js'
},
output:{
filename: '[name].js',
path: path.resolve(__dirname,'dist')
}
}
1 | <script type="text/javascript" src="main.js"></script> |
如果我想要在打包之后注入的js前面带一个域名,可以用publicPath配置项1
2
3output:{
publicPath: 'http://cdn.com.cn'
}
打包之后所有引入的js前面都带有域名了1
2<script type="text/javascript" src="http://cdn.com.cn/main.js"></script>
<script type="text/javascript" src="http://cdn.com.cn/sub.js"></script>
四、SourceMap的配置
4.1 SourceMap
在mode为development时,默认SourceMap时被配进去了,主动关闭SourceMap:devtool:'none'
如想打包后出现报错,要想知道src目录下的文件哪一行代码出错而不是打包文件dist下的哪一行出错,例:
- 当前index.js文件中的第一行出错
- 现在知道dist目录下main.js文件第96行出错,
SourceMap
是一个映射关系,它知道dist目录下main.js文件第96行的出错实际上对应的是src目录下index.js文件中的第一行1
2
3
4
5
6
7module.export{
mode: 'development',
devtool: 'source-map'
entry: {
main: './src/index.js'
}
}
它会生成一个map文件,他的内容是一种编码方式,用来对应文件的映射关系。
4.2 inline-source-map
用inline-source-map
的话,就不会在dist中生成这样的map文件,而是直接以base64形式放在了dist中的main.js的底部。1
devtool: 'inline-source-map'
4.3 cheap-inline-source-map
当我们遇到代码量很大的时候,inline-source-map会告诉我们错误会精确的告诉我们在第几行第几列,但是这样的一个映射比较耗费性能,代码出错了,我只希望你告诉我在第几行就可以,如果是cheap-inline-source-map
,那么久不会把错误的第几行第几列告诉我们了,这样就可以在一定程度上提升打包的性能。1
devtool: 'cheap-inline-source-map'
4.4 cheap-module-inline-source-map
不仅管业务代码的错误,还管loader等一些插件上的代码错误cheap-module-inline-source-map
1
devtool: 'cheap-module-inline-source-map'
4.5 eval
eval一样也可以找到错误第几行,main.js底部不会有map的编码,取而代之的是1
eval("console.log('hello world');\n\n//# sourceURL=webpack....")
这样一种形式。eval这种方式是执行效率最快的,性能最高的打包方式,但是针对于比较复杂的代码用eval提示出来的内容可能并不全面。
所以最佳的使用方式是:
如果在开发环境中(development),建议使用devtool:cheap-module-eval-source-map;
如果把代码放到线上环境了(production),建议使用devtool:cheap-module-source-map;
五、使用 WebpackDevServer 提升开发效率
5.1 安装
1 | npm run watch |
webpack watch会监听我们打包的文件,只要他要打包的源文件代码发生变化,就会自动的重新打包,从而提升打包效率。
安装WebpackDevServer:1
npm install webpack-dev-server -D
1 | devServer:{ |
1 | "scripts":{ |
运行:npm run strat,此时会有一个localhost
WebpackDevServer相较于webpack watch,不但一样可以监听到源文件代码的变化,重新帮我们打包,它还会自动刷新浏览器,更方便地提升开发效率。1
2
3
4devServer:{
contentBase: './dist'
open: true
}
open是指自动打开一个浏览器,自动地访问地址http://localhost:8080
六、Hot Module Replacement 热模块更新
它可以在我们写css的时候方便我们调试CSS1
2
3
4
5
6
7devServer:{
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true
}
📁webpack.config.js1
const webpack = require('webpack');
1 | plugins:[ |
我们都知道webpack-dev-server
在代码改变之后它会自动打包并刷新页面,那有时候我们只更改了样式代码,所以用HotModuleReplacementPlugin
就直接把更改的CSS代码给渲染到页面上而不会整一个重新自动打包并刷新页面了,这样就很方便调试。
在配置好之后最好重启一下命令npm run start
例:counter模块里面的js代码是点击数字累加1;number模块里面的代码是显示数字1000;想要实现的效果是当点击数字1,累加到10,这时改变数字1000为2000,在页面上不重新刷新,10还是10,1000已经变为20001
2
3
4
5
6
7
8
9
10
11
12
13import counter from './counter';
import number from './number';
counter();
number();
//如果配置了HotModuleReplacementPlugin,这个时候还需要正在index.js写判断语句
if (module.hot){
modele.hot.accept('./number',()=>{
document.body.removeChild(document.getElementById('number'))
number();
})
}
七、使用 Babel 处理 ES6 语法
bable可以将js语法书写的代码(ES6)输出为浏览器兼容的代码(ES5)
7.1 安装:
1 | npm install --save-dev babel-loader @bable/core |
在webpack.config.js中的rules加一条:
📁webpack.config.js1
2
3
4
5module:{
rules:[
{test:/\.js$/,exclude:/node_modules/,loader:"bable-loader"}
]
}
exclude表示如果你的js文件在node_modules里面,就不使用bable-loader了,因为node_modules里面的代码是第三方的代码,没必要对这些第三方代码进行ES6→ES5的操作,其实第三方早就已经帮我们做好了这一步。所以文件在src目录下的,就会使用bable-loader
7.2 preset-env
preset-env包含了所有ES6→ES5的规则
安装:1
npm install @bable/preset-env --save-dev
配置:1
2
3
4
5
6
7
8
9
10
11
12module: {
rules:[
{
test: /\.js$/,
exclude: /node_modules/,
loader: "bable-loader",
options:{
presets:["@bable/preset-env"]
}
}
]
}
preset-env
语法翻译只是翻译了一部分,虽然箭头函数已经变成普通函数的形式了,但是像map这种方法并不能让所有的浏览器兼容。所以这个时候我们需要借助polyfill
帮我们对低版本浏览器的补充。
7.3 polyfill
安装:1
npm install --save @bable/polyfill
📁 src index.js1
import "@bable/polyfill"
这个时候在presets里配置useBuiltIns : 'usage'
,这样的话就用哪个打包哪个,没有用到map函数,就不会把map函数翻译出来,这样就会减小打包体积。1
2
3
4
5
6
7
8
9
10
11
12module: {
rules:[
{
test: /\.js$/,
exclude: /node_modules/,
loader: "bable-loader",
options:{
presets:[["@bable/preset-env"],{useBuiltIns:'usage'}]
}
}
]
}
假如运行在Chrome浏览器上,由于Chrome浏览器67以上的版本很好的支持了ES6,再转换成ES5没有意义,当版本大于67时不用preset-env打包。1
2
3
4
5
6
7
8
9options:{
presets:[
["@bable/preset-env"],
{useBuiltIns:'usage'},
targets:{
chrome:"67"
}
]
}