这次我们打算做一个SPA应用的样板文件(boilerplate),UI框架使用React(ES6+JSX),UI组件库使用antd,样式语言使用less,并引入自定义字体图标。
我们使用的工具有:
webpack@4.27.1
webpack-cli@3.1.2
webpack-dev-server@3.1.10
准备工作
- 安装webpack、webpack-cli、webpack-dev-server
$ npm i -D webpack webpack-cli webpack-dev-server
- 确定项目目录结构
├─config
└─src
├─common
│ └─utils
│ └─index.js
├─sys
│ ├─home
│ │ └─index.js
│ └─router.js
├─index.html
└─index.js
package.json
README.md
config
目录存放配置文件
src
目录下存放代码,common是公共代码,sys里是业务代码
配置
下面开始正式配置脚手架
- 处理js文件
- 处理样式文件
- 处理图片
- 处理字体文件
- 引入antd
- 管理输出
- 开发服务配置
具体流程:
1. 处理js文件
webpack主要是用来编译JavaScript模块,内置支持ES2015中的import
和export
,但是webpack编译时只会处理这两个语法,其他语法会原封不动保留,要想完全使用ES2015的特性,需要引入babel-loader这个模块处理器
首先安装loader和babel
$ npm i -D babel-loader @babel/core @babel/preset-env
然后在webpack.config.js
文件中的module参数下去配置js文件的处理
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
use: 'babel-loader'
}
]
}
}
配置好后可以在js文件中写入任意的ES2015代码,执行npm run build
,看看webpack是否能正确编译
接下来配置react,需要安装react
库、react-dom
库和babel转义react的库@babel/preset-react
$ npm i -D react react-dom @babel/preset-react
然后在.babelrc
中添加关于react的配置
# .babelrc
{
"presets": [
"@babel/react"
]
}
此时就可以在代码中愉快的使用react的jsx语法了
2. 处理样式文件
webpack除了可以处理JavaScript,还可以通过loader来处理其他任意类型的模块
我们在项目中使用的样式语言是less,所以需要使用less-loader来处理。首先进行安装loader
$ npm i -D less-loader css-loader style.loader mini-css-extract-plugin
然后在webpack.config.js
文件中的module参数下去配置
# webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const styleLoader = devMode ? 'style-loader' : MiniCssExtractPlugin.loader;
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [styleLoader, 'css-loader', 'less-loader'],
}
]
}
}
此时你可能迫不及待的写好了样式,想要验证一下,执行编译命令后却发现失败了。提示can't find module less
。因为less语言是需要安装less库才能处理
$ npm i -D less
安装完成后再执行编译命令就会发现成功了!
一般要对业务组件内的样式开启css module。
# webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const styleLoader = devMode ? 'style-loader' : MiniCssExtractPlugin.loader;
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [styleLoader, {
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:8]',
},
}, 'postcss-loader', 'less-loader'],
exclude: /node_modules/,
}
]
}
}
3. 处理图片
页面开发经常需要图片,使用file-loader
和url-loader
,可以轻松处理图片,如果图片尺寸小于8192byte,将会转成dataUrl的格式,超过的话默认调用file-loder转换成静态资源
首先是安装loader
$ npm i -D file-loader url-loader
配置
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
name: 'img/[name].[hash:8].[ext]',
limit: 8192,
},
}],
}
]
}
}
4. 处理字体文件
字体文件同样可以使用file-loader
处理,现在我们可以直接在webpack.config.js
添加对字体文件的处理
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [{
loader: 'file-loader',
options: {
name: 'iconfont/[name].[ext]',
},
}],
}
]
}
}
5. 引入antd
开发需要使用UI组件库antd,antd里面既有js代码,又有样式代码(less),所以我们需要针对这两种语言分别进行配置。在antd官网里也有介绍相关配置
antd的js需要用babel-loader处理,样式代码(less)使用less-loader处理
首先安装antd和处理antd实现按需加载的插件babel-plugin-import
$ npm i -D antd babel-plugin-import
babel-loader的配置写在.babelrc
中,在.babelrc
中添加插件
#.babelrc
{
"plugins": [
["import", { "libraryName": "antd", "style": true }]
]
}
处理样式文件,同第二步类似
# webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.less$/,
include: path.resolve(__dirname, 'node_modules/antd'),
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
}
]
}
}
6. 管理输出
以前我们开发都需要将js、css等手动引入到index.html
中,但是随着应用复杂度上升,对文件名使用hash处理,并且导出到多个bundle中,手动对index.html
管理就变得很困难,所以可以借助一些插件来处理这个过程。
入口文件是src目录下的index.js文件
,出口是dist目录
。
# webpack.config.js
const ROOT_PATH = path.resolve(__dirname, '..');
const SRC_PATH = path.resolve(ROOT_PATH, 'src');
const BUILD_PATH = path.resolve(ROOT_PATH, 'dist');
const devMode = process.env.NODE_ENV !== 'production';
const publicPath = devMode ? '' : './';
module.exports = {
context: SRC_PATH,
entry: {
index: './index.js',
vendor: ['react', 'react-dom'],
},
output: {
publicPath,
path: BUILD_PATH,
filename: '[name].[hash:8].js',
chunkFilename: '[name].[chunkhash:8].js'
},
}
如果我们更改了我们的一个入口起点的名称,甚至添加了一个新的名称,会发生什么?生成的包将被重命名在一个构建中,但是我们的index.html文件仍然会引用旧的名字。我们用 HtmlWebpackPlugin
来解决这个问题。
# webpack.config.js
const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebPackPlugin({
template: 'index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
removeComments: true,
},
hash: true,
})
]
}
7. devServer
开发过程中需要不断调试代码,webpack提供了一个开发服务器webpack-dev-server
,内部自带了模块热替换(HMR)的功能,可以极大地提升开发效率。
前面我们已经安装了webpack-dev-server
,接下来只需要在webpack.config.js
中进行配置即可,配置如下:
# webpack.config.js
module.exports = {
devServer: {
port: 2333,
open: false,
historyApiFallback: true,
proxy: {
'/api/*': {
target: 'http://www.demo.com',
secure: false,
changeOrigin: true,
},
}
},
}