webpack 从0到1
webpack 从0到1
webpack 是什么?
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
一些基本的概念
mode 开发模式
webpack 提供 mode 配置选项,配置 webpack 相应模式的内置优化。
// webpack.production.config.js
module.exports = {
+ mode: 'production',
}
入口文件(entry)
入口文件,类似于其他语言的起始文件。比如:c 语言的 main 函数所在的文件。
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
可以在 webpack 的配置文件中配置入口,配置节点为: entry,当然可以配置一个入口,也可以配置多个。
输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
插件(plugins)
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
webpack 的安装
本地安装 webpack
$ cnpm i -D webpack
# 如果你使用 webpack 4+ 版本,你还需要安装 CLI。
cnpm i -D webpack-cli
安装完成后,可以添加cnpm的script脚本
// package.json
"scripts": {
"start": "webpack --config webpack.config.js"
}
全局安装 webpack(不推荐)
将使 webpack 在全局环境下可用:
cnpm i -g webpack
注意:不推荐全局安装 webpack。这会将你项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中,可能会导致构建失败。
快速入门
- 第一步:创建项目结构
首先我们创建一个目录,初始化 cnpm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack):
mkdir webpack-demo && cd webpack-demo
cnpm init -y
cnpm install webpack webpack-cli --save-dev
项目结构
webpack-demo
+ |- package.json
+ |- /dist
+ |- index.html
+ |- /src
+ |- index.js
- 第二步:安装 loadash 依赖和编写 js 文件
cnpm install --save lodash
编写:src/index.js 文件
import _ from 'lodash';
function createDomElement() {
var dom = document.createElement('div');
dom.innerHTML = _.join(['webpack', '使用', 'demo'], '');
return dom;
}
document.body.appendChild(createDomElement());
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>start</title>
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
- 第三步:编写 webpack 配置文件
根目录下添加 webpack.config.js文件。
webpack-demo
|- package.json
+ |- webpack.config.js
|- /dist
|- index.html
|- /src
|- index.js
webpack.config.js 内容如下:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
}
};
- 执行构建任务
直接执行构建任务:
npx webpack
打开: dist/index.html 可以查看到页面的结果。
非 js 文件怎么办?
webpack 最出色的功能之一就是,除了 JavaScript,还可以通过 loader 引入任何其他类型的文件
加载 CSS 文件
- 第一步: 安装 css 和 style 模块解析的依赖
style-loader和css-loader
cnpm i -D style-loader css-loader
- 第二步: 添加 css 解析的 loader
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', // inject
'css-loader'] // parse stylesheet
}
]
}
};
-
css-loader: 将import './main.css'中的样式解析出来 -
style-loader: 把 js 中引入的 css 内容 注入到 html 标签中 -
第三步: 编写 css 文件和修改 js 文件
在 src 目录中添加 style.css文件
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- style.css
|- index.js
|- /node_modules
src/style.css
.hello {
color: red;
}
修改 js 文件
import _ from 'lodash';
+ import './style.css';
function createDomElement() {
let dom = document.createElement('div');
dom.innerHTML = _.join(['webpack', '使用', ' demo'], '');
+ dom.className = 'hello';
return dom;
}
document.body.appendChild(createDomElement());
最后重新打开 dist 目录下的 index.html, 发现文字变成了红色.
module Rule
- Rule 条件详解
- 字符串:匹配输入必须以提供的字符串开始。是的。目录绝对路径或文件绝对路径。
- 正则表达式:test 输入值。
- 函数:调用输入的函数,必须返回一个真值(true)以匹配。
- 条件数组:至少一个匹配条件。
- 对象:匹配所有属性。每个属性都有一个定义行为。
Rule.test
- { test: Condition }:匹配特定条件。一般是提供一个正则表达式或正则表达式的数组,但这不是强制的。
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
...
};
其他的条件比如:
{ include: Condition }:匹配特定条件。一般是提供一个字符串或者字符串数组,但这不是强制的。{ exclude: Condition }:排除特定条件。一般是提供一个字符串或字符串数组,但这不是强制的。{ and: [Condition] }:必须匹配数组中的所有条件{ or: [Condition] }:匹配数组中任何一个条件{ not: [Condition] }:必须排除这个条件
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
include: [
path.resolve(__dirname, "app/styles"),
path.resolve(__dirname, "vendor/styles")
],
use: ['style-loader', 'css-loader']
}
]
}
...
};
Rule.use
应用于模块指定使用一个 loader。
Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured).
加载器可以链式传递,从后往前.
use: [
'style-loader',
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
];
传递字符串(如:use: [ "style-loader" ])是 loader 属性的简写方式(如:use: [ { loader: "style-loader "} ])。
加载 Sass 文件
加载 Sass 需要sass-loader。
安装
cnpm i -D sass-loader node-sass webpack
使用:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
}]
}
};
创建 Source Map
css-loader和sass-loader都可以通过该 options 设置启用 sourcemap。
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
sourceMap: true
}
}, {
loader: "sass-loader",
options: {
sourceMap: true
}
}]
}]
}
};
PostCSS 处理 loader(附带:添加 css3 前缀)
PostCSS是一个 CSS 的预处理工具,可以帮助我们:给 CSS3 的属性添加前缀,样式格式校验(stylelint),提前使用 css 的新特性比如:表格布局,更重要的是可以实现 CSS 的模块化,防止 CSS 样式冲突。
我们常用的就是使用 PostCSS 进行添加前缀,以此为例:
安装
cnpm i -D postcss-loader autoprefixer
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer')({ browsers: ['> 0.15% in CN'] }) // 添加前缀
]
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}
]
}
};
样式表抽离成专门的单独文件
首先以下的 css 的处理我们都把 mode 设置为 production。
webpack4 开始使用: mini-css-extract-plugin插件, 1-3 的版本可以用: extract-text-webpack-plugin
抽取了样式,就不能再用
style-loader注入到 html 中了。
cnpm install -D mini-css-extract-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production'; // 判断当前环境是开发环境还是 部署环境,主要是 mode属性的设置值。
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css', // 设置最终输出的文件名
chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
})
]
};
再次运行打包:
在 dist 目录中已经把 css 抽取到单独的一个 css 文件中了。修改 html,引入此 css 就能看到结果了。
压缩 CSS
webpack5 貌似会内置 css 的压缩,webpack4 可以自己设置一个插件即可。
压缩 css 插件:optimize-css-assets-webpack-plugin
安装
cnpm i -D optimize-css-assets-webpack-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
})
],
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})]
}
};
JS 压缩
压缩需要一个插件: uglifyjs-webpack-plugin, 此插件需要一个前提就是:mode: 'production'.
安装
cnpm i -D uglifyjs-webpack-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
})
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
}
};
解决 文件名字哈希变化的问题
HtmlWebpackPlugin插件,可以把打包后的 CSS 或者 JS 文件引用直接注入到 HTML 模板中,这样就不用每次手动修改文件引用了。
安装
cnpm i -D html-webpack-plugin
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
}),
new HtmlWebpackPlugin({
title: 'AICODER 全栈线下实习', // 默认值:Webpack App
filename: 'main.html', // 默认值: 'index.html'
template: path.resolve(__dirname, 'src/index.html'),
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true // 移除属性的引号
}
})
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
}
};
清理 dist 目录
每次构建,我们的 /dist 文件夹都会保存生成的文件,然后就会非常杂乱。
通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法
clean-webpack-plugin 是一个比较普及的管理插件,让我们安装和配置下。
cnpm install -D clean-webpack-plugin
webpack.config.js
const path = require('path');
....
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
+ new CleanWebpackPlugin()
...
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
...
};
现在执行 cnpm run build
加载图片与图片优化
在 css 文件或者 sass 文件中添加如下代码
$red: #900;
$size: 20px;
.box {
height: 30px*2;
font-size: $size;
transform: translate3d( 0, 0, 0 );
+ background: url('../static/1.jpeg')
}
运行打包发现如下错误:
ERROR in ./src/static/1.jpeg 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
解决方案:file-loader处理文件的导入
cnpm i -D file-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
+ {
+ test: /\.(png|svg|jpg|gif)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
此时运行打包,发现 dist 目录多了一个图片文件.
那更进一步,图片如何进行优化呢?
image-webpack-loader可以帮助我们对图片进行压缩和优化。
cnpm i -D image-webpack-loader
使用:webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
use: [
'file-loader',
+ {
+ loader: 'image-webpack-loader',
+ options: {
+ mozjpeg: {
+ progressive: true,
+ quality: 65
+ },
+ optipng: {
+ enabled: false,
+ },
+ pngquant: {
+ quality: '65-90',
+ speed: 4
+ },
+ gifsicle: {
+ interlaced: false,
+ },
+ webp: {
+ quality: 75
+ }
+ }
+ },
]
}
]
}
};
此时在运行 webpack,发现会 生成的图片的大小会被压缩很多。
更进一步处理图片
url-loader功能类似于 file-loader,可以把 url 地址对应的文件,打包成 base64 的 DataURL,提高访问的效率。
如何使用:
cnpm i --D url-loader
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|jpeg|ico|woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader', // 根据图片大小,把图片优化成base64
options: {
limit: 10000
}
},
{
loader: 'image-webpack-loader', // 先进行图片优化
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
}
]
}
};
字体的处理(同图片)
处理跟图片一致。
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
开发相关辅助
合并两个webpack的js配置文件
开发环境(development)和生产环境(production)配置文件有很多不同点,但是也有一部分是相同的配置内容,如果在两个配置文件中都添加相同的配置节点,
就非常不爽。
webpack-merge 的工具可以实现两个配置文件进合并,这样我们就可以把 开发环境和生产环境的公共配置抽取到一个公共的配置文件中。
安装:
cnpm i -D webpack-merge
例如:
project
webpack-demo
|- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
|- /dist
|- /src
|- index.js
|- math.js
|- /node_modules
webpack.common.js
+ const path = require('path');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+ module.exports = {
+ entry: {
+ app: './src/index.js'
+ },
+ plugins: [
+ new CleanWebpackPlugin(['dist']),
+ new HtmlWebpackPlugin({
+ title: 'Production'
+ })
+ ],
+ output: {
+ filename: '[name].bundle.js',
+ path: path.resolve(__dirname, 'dist')
+ }
+ };
webpack.dev.js
+ const merge = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+ devtool: 'inline-source-map',
+ devServer: {
+ contentBase: './dist'
+ }
+ });
webpack.prod.js
+ const merge = require('webpack-merge');
+ const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+ plugins: [
+ new UglifyJSPlugin()
+ ]
+ });
js 使用 source map
当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置。例如,如果将三个源文件(a.js, b.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会简单地指向到 bundle.js。
使用 inline-source-map 选项,这有助于解释说明 js 原始出错的位置。(不要用于生产环境):
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
+ devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
监控文件变化,自动编译。使用观察模式
每次修改完毕后,都手动编译异常痛苦。最简单解决的办法就是启动watch。
npx webpack --watch
当然可以添加到 cnpm 的 script 中
package.json
{
"name": "development",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "npx webpack --watch",
"build": "npx webpack"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
如何能不刷新页面,自动更新变化呢?
使用 webpack-dev-server 和热更新
webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。
安装
cnpm i -D webpack-dev-server
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
+ devServer: {
+ contentBase: './dist'
+ },
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
启动此 webserver:
webpack-dev-server --open
devServer: {
clientLogLevel: 'warning', // 可能的值有 none, error, warning 或者 info(默认值)
hot: true, // 启用 webpack 的模块热替换特性, 这个需要配合: webpack.HotModuleReplacementPlugin插件
contentBase: path.join(__dirname, "dist"), // 告诉服务器从哪里提供内容, 默认情况下,将使用当前工作目录作为提供内容的目录
compress: true, // 一切服务都启用gzip 压缩
host: '0.0.0.0', // 指定使用一个 host。默认是 localhost。如果你希望服务器外部可访问 0.0.0.0
port: 8080, // 端口
open: true, // 是否打开浏览器
overlay: { // 出现错误或者警告的时候,是否覆盖页面线上错误消息。
warnings: true,
errors: true
},
publicPath: '/', // 此路径下的打包文件可在浏览器中访问。
quiet: true, // necessary for FriendlyErrorsPlugin. 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
watchOptions: { // 监视文件相关的控制选项
poll: true, // webpack 使用文件系统(file system)获取文件改动的通知。在某些情况下,不会正常工作。例如,当使用 Network File System (NFS) 时。Vagrant 也有很多问题。在这些情况下,请使用轮询. poll: true。当然 poll也可以设置成毫秒数,比如: poll: 1000
ignored: /node_modules/, // 忽略监控的文件夹,正则
aggregateTimeout: 300 // 默认值,当第一个文件更改,会在重新构建前增加延迟
}
}
如何启用热更新呢?
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
+ const webpack = require('webpack');
module.exports = {
entry: {
app: './src/index.js'
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
+ hot: true
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Hot Module Replacement'
}),
+ new webpack.NamedModulesPlugin(), // 更容易查看(patch)的依赖
+ new webpack.HotModuleReplacementPlugin() // 替换插件
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
JS启用babel转码
虽然现代的浏览器已经兼容了96%以上的ES6的语法了,但是为了兼容老式的浏览器(IE8、9)我们需要把最新的ES6的语法转成ES5的。那么babel的loader就出场了。
安装
cnpm i -D babel-loader@7 babel-core babel-preset-env
用法
在webpack的配置文件中,添加js的处理模块。
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/, // 加快编译速度,不包含node_modules文件夹内容
use: {
loader: 'babel-loader'
}
}
]
}
然后,在项目根目录下,添加babel的配置文件 .babelrc.
.babelrc文件如下:
{
"presets": ["env"]
}
最后,在入口js文件中,添加ES6的新语法:
() => {
console.log('hello world');
}
最后打包:
npx webpack
Babel优化
babel-loader可以配置如下几个options:
-
cacheDirectory:默认值为 false。当有设置时,指定的目录将用来缓存 loader 的执行结果。之后的 webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel 重新编译过程(recompilation process)。如果设置了一个空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 将使用默认的缓存目录 node_modules/.cache/babel-loader,如果在任何根目录下都没有找到 node_modules 目录,将会降级回退到操作系统默认的临时文件目录。 -
cacheIdentifier:默认是一个由 babel-core 版本号,babel-loader 版本号,.babelrc 文件内容(存在的情况下),环境变量 BABEL_ENV 的值(没有时降级到 NODE_ENV)组成的字符串。可以设置为一个自定义的值,在 identifier 改变后,强制缓存失效。 -
forceEnv:默认将解析 BABEL_ENV 然后是 NODE_ENV。允许你在 loader 级别上覆盖 BABEL_ENV/NODE_ENV。对有不同 babel 配置的,客户端和服务端同构应用非常有用。
注意:sourceMap 选项是被忽略的。当 webpack 配置了 sourceMap 时(通过 devtool 配置选项),将会自动生成 sourceMap。
babel 在每个文件都插入了辅助代码,使代码体积过大.babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。 默认情况下会被添加到每一个需要它的文件中。你可以引入 babel runtime 作为一个独立模块,来避免重复引入。
安装:
cnpm i -D babel-plugin-transform-runtime babel-runtime
配置:
webpack.config.js
rules: [
// 'transform-runtime' 插件告诉 babel 要引用 runtime 来代替注入。
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
]
修改.babelrc
{
"presets": ["env"],
"plugins": [
["transform-runtime", {
"helpers": true,
"polyfill": true,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}
此时,webpack打包的时候,会自动优化重复引入公共方法的问题。
ESLint校验代码格式规范
安装
cnpm i -D eslint eslint-loader
# 以下是用到的额外的需要安装的eslint的解释器、校验规则等
cnpm i -D babel-eslint standard
使用
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
// eslint options (if necessary)
fix: true
}
},
],
},
// ...
}
eslint配置可以直接放到webpack的配置文件中,也可以直接放到项目根目录的 .eslintrc中文档。
// .eslintrc.js
// https://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint'
},
env: {
browser: true
},
extends: [
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
'standard'
],
globals: {
NODE_ENV: false
},
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
// 添加,分号必须
semi: ['error', 'always'],
'no-unexpected-multiline': 'off',
'space-before-function-paren': ['error', 'never'],
// 'quotes': ["error", "double", { "avoidEscape": true }]
quotes: [
'error',
'single',
{
avoidEscape: true
}
]
}
};
此时eslint的配置就结束了。
至此, 本篇博客结束
浙公网安备 33010602011771号