这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
前面我们已经讨论过如何让 webpack 处理 CSS,并提取出文件,以及图片的处理。接着我们讨论一下在 webpack 中配置 babel。babel 是一个平台,可以把高级的 JS 语法转换成低版本的 JS 实现,同时还可以处理 JSX 语法。 此外,我们还可以讨论一下 webpack 的常规优化配置项;
一、 配置 babel
1.1 基础配置
使用 babel 需要安装 babel-loader、@babel/core、@babel/preset-env。如果有更高级的语法还需要安装 preset 或者 babel的插件;
yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react
- 修改一下 index.js
向 index.js 中增加箭头函数和 react 的 jsx(如果不熟悉 react 可以忽略 react 部分内容);
+ import React from 'react'
+ import { render } from 'react-dom'
import './index.css';
import './index.less'
+ let a = () => {
+ console.log('arrow function')
+ };
a();
document.addEventListener('DOMContentLoaded', function () {
let div = document.createElement('div');
div.innerHTML = 'Hello World';
document.body.appendChild(div);
div = null;
});
+ let p2 = <p>这是一个 jsx 元素</p>;
+ render(p2, document.getElementById('root'));
- 效果如图
1.2 使用 ES 提案语法
在开发的过程中我们经常使用一些 ES 的实验阶段的语法,例如装饰器、class-properties、async/await、generator 函数等;但是 babel 的 preset 中并不包含这些内容,所以还需要额外的配置一些 babel 插件;@babel/plugin-proposal-decorators、 @babel/plugin-proposal-class-properties、 @babel/plugin-transform-runtime 等插件同样需要安装;
- 安装插件(以实际项目中为准,用到哪些特性就安装对应特性):
yarn add @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime -D
- 新增 js 文件 sthjs/a.js
// decorator
function log(target) {
console.log(target)
}
@log
class A {
constructor() {
this.test = 'test decorator'
}
}
// class properties
class B {
b = 1;
x = 'test class properties';
}
let b = new B();
console.log(b.x)
// 3. async/await
async function getImg() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 2000)
})
}
getImg();
// 4. generator
function * gen() {
yield 1;
yield 2;
yield 3;
return 4;
}
let it = gen();
console.log(it.next());
for (let i of it) {
console.log(i)
}
- 在 index.js 中引入上面的 a.js
import React from 'react'
import { render } from 'react-dom'
+ import './sthjs/a.js'
import './index.css';
import './index.less'
let a = () => {
console.log('arrow function')
};
a();
document.addEventListener('DOMContentLoaded', function () {
let div = document.createElement('div');
div.innerHTML = 'Hello World';
document.body.appendChild(div);
div = null;
});
let p2 = <p>这是一个 jsx 元素</p>;
render(p2, document.getElementById('root'));
-
在 webpack.config.js 的 babel-loader 配置增加 plugins:
-
plugins: Array
- ['@babel/plugin-proposal-decorators', { legacy: true }], 使用装饰器
- ['@babel/plugin-proposal-class-properties', { loose: true }], 使用 class-properties
- ['@babel/plugin-transform-runtime'] 使用 async/await/generator
-
效果如图
二、 压缩 JS 、CSS 文件
webpack 同样支持优化代码,其中包含压缩混淆 JS 、压缩 CSS 等功能,下面我们具体实践一番;优化需要在 webpack 的配置文件中增加 optimization 字段;压缩合并同样依赖于两个插件,所以同样先安装他们;
在此之前还要说一个配置,mode 字段,该字段有两个值:
- development 开发模式,不会压缩混淆代码
- production 生产模式,会自动混淆代码
2.1 安装 optimize-css-assets-webpack-plugin 和 uglifyjs-webpack-plugin
yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
2.2 修改配置文件
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); // 抽离 css文件
+ const OptimizeCSSAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩合并 css 文件
+ const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin'); // 压缩混淆 js 文件
module.exports = {
entry: './src/index.js',
+ mode: 'production', // 'development' 表示开发模式,不压缩代码;'production' 表示生产模式,压缩混淆代码
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
port: 3000,
// open: true,
progress: true,
proxy: {
'/api': {
target: 'http://domain.com/somet/api',
changeOrigin: true,
secure: false
}
}
},
module: {
rules: [
{
test: /.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }], // 使用装饰器
['@babel/plugin-proposal-class-properties', { loose: true }], // 使用 class-properties
['@babel/plugin-transform-runtime'] // 使用 async/await/generator
]
}
},
exclude: /node_modules/
},
{
test: /.css$/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader'
]
},
{
test: /.less$/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /.(jpeg|png|jpg)$/,
use: {
loader: 'url-loader',
options: {
limit: 5 * 1024,
outputPath: '/img/'
}
}
},
{
test: /.(htm|html)$/,
use: 'html-withimg-loader' // 处理 html 中的 img 引用的图片
}
]
},
plugins: [
new HTMLWebpackPlugin({
template: './src/index.html', // 需要引入输出文件的 html 文件模板
hash: true, // 给引入的 js 加hash
filename: 'index.html', // 输出的 html 文件的名字(插件会把模板 html 复制到输出目录中)
minify: { // 压缩优化输出的 html 文件配置
removeAttributeQuotes: true, // 删除行内属性的双引号
collapseWhitespace: true // 删除换行,使内容保持在一行
}
}),
// 抽离 css 文件
new MiniCSSExtractPlugin({
filename: 'css/main.css'
})
],
+ // 配置优化配置项
+ optimization: {
+ minimizer: [
+ new OptimizeCSSAssetsWebpackPlugin(), // 压缩 CSS 文件,配置该插件后需要配置如下的 UglifyjsWebpackPlugin
+ new UglifyjsWebpackPlugin({
+ cache: true, // 是否缓存
+ parallel: true, // 是否并发打包
+ sourceMap: true // 是否开启 sourceMap
+ })
+ ]
+ }
}
- 效果如图