一.npm init 初始化环境创建package.json
二.安装wepack
npm install --D webpack webpack-dev-server webpack-cli
webpack4.x要求安装webpack-cli
webpack-dev-server是一个基于Express框架的Node.js服务器。它还提供了一个客户端的运行环境,会被注入到页面代码中执行,并通过Socket.IO与服务器通信。
服务器端的每次改动与重新构建都会被通知到页面上。还提供了如模块替换这样强大的功能。
复制代码
三.webpack基本配置
1.项目根目录新建build文件夹,创建webpack.config.js
const path = require("path");
function resolve(dir) {
return path.resolve(__dirname, dir)
}
module.exports = {
// 指定构建环境
mode:"development",
// 入口
entry: {
app: "./src/index"
},
// 出口
output: {
path : resolve("../dist"),
filename: "js/[name].[hash].js",
publicPath: "/" // 打包后的资源的访问路径前缀
},
// 模块
module:{
},
// 插件
plugins:[
],
// 开发环境本地启动的服务配置
devServer: {
}
}
复制代码
2.编写,配置html模板,实现html模板的打包,安装插件
npm install -D html-webpack-plugin
在根目录下新建index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>mydemo</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
复制代码
3.为了区分开发环境和生产环境,下面我们一步一步抽取wenpack公共配置
分别创建 utils.js ,webpack.base.config.js , webpack.dev.config.js , webpack.prod.config.js
四.babel配置
npm install -D @babel/core @babel/preset-env @babel/preset-react
npm install -D @babel/plugin-transform-runtime @babel/runtime @babel/runtime-corejs2
复制代码
-
==@babel/core== babelbabel的核心库
-
==@babel/preset-env== 把es6,es7语法转换成es5。bebel7以上的版本只用这一个预设包就可以实现语法的转换,已经废弃了preset-stage-0,preset-stage-1,preset-stage-2等这些包。但是这个包还不能转换es6,es7的一些新特性比如Array.includes(),这就需要我们使用@babel/plugin-transform-runtime了
-
==@babel/preset-react== 把react语法转换为es5
-
==@babel/plugin-transform-runtime== 支持一些es6,es7的新语法
那么安装完了,我们需要添加babel的配置了,在项目目录创建.babelrc,配置内容如下
{
"presets": [
["@babel/preset-env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime",{
"corejs": 2, // polyfill 需要使用@babel/runtime-corejs2
"useBuildIns":"usage", //按需引入,即使用什么新特性打包什么新特性, 可以减小打包的体积
}]
]
}
复制代码
五.loader配置
- 安装babel-loader
npm install -D babel-loader
复制代码
- style-loader,css-loader编译css文件
npm install -D style-loader css-loader
复制代码
- url-loader file-loader引入文件路径(图片,字体)
npm install -D url-loader file-loader
复制代码
- less-loader
npm install -D less less-loader
复制代码
安装完这些包之后,我们需要在webpacl.base.config.js添加打包编译构建规则
在module下添加rules属性
- postcss-loader + autoprefixer
npm install postcss-loader --save-dev
npm install autoprefixer --save-dev
复制代码
rules: [
{
test: /\.(js|jsx)$/,//一个匹配loaders所处理的文件的拓展名的正则表达式,这里用来匹配js和jsx文件(必须)
exclude: /node_modules/,//屏蔽不需要处理的文件(文件夹)(可选)
loader: 'babel-loader',//loader的名称(必须)
},
{
test: /\.css$/,
use: [
{
loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader, // 创建 <style></style>
},
{
loader: 'css-loader', // 转换css
},
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
{
// 开发环境不要MiniCssExtractPlugin,因为它不会热更新
loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
},
'postcss-loader',
{
loader: 'less-loader', // 编译 Less -> CSS
},
],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
include: [resolve('static'), resolve('src')],
options: {
limit: 10000, // url-loader 包含file-loader,这里不用file-loader, 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
name: 'static/img/[name].[hash:7].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
include: [resolve('static'), resolve('src')],
loader: 'url-loader',
options: {
limit: 10000, // 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
name: 'static/fonts/[name].[hash:7].[ext]'
}
}
]
但我们的项目中有的图片列表是用v-for遍历出来的,也就是url放到了js中(vue文件的data里),
这样就不能被base64编码了,url-loader只会去编译html以及css中的image。
所以可以使用import图片的方式通过一个变量去接受,然后将这些变量放到v-for中去渲染。
复制代码
npm run build 后查看dist应用
npm install -g http-server
安装成功之后,cd dist目录,执行http-server命令
http-server -p 443 指定端口
复制代码
六.webpack react配置
- 引入安装react
npm install -S react react-dom
复制代码
2.react-router4.x
npm install -S react-router-dom
复制代码
npm install -D copy-webpack-plugin
复制代码
七.anted按需引入
npm install antd --save
npm install babel-plugin-import --save-dev
复制代码
高版本的antd官方把图标库也构建到release包,所以导致打包变得很大,仅仅icon图标库就有几百KB,请看下图。
八、打包优化
- react路由的异步加载
- css处理
- 使用mini-css-extract-plugin把css从bundle包中抽取
- 使用optimize-css-assets-webpack-plugin压缩css代码
- 使用postcss-loader,autoprefixer对浏览器兼容性的css代码加前缀
- js的处理
- 使用uglifyjs-webpack-plugin代码压缩
- 多线程打包:happypack
- 拆包,js的bundle包的提取(拆包)
1.分析打包的文件大小原因
npm install -D clean-webpack-plugin webpack-bundle-analyzer
clean-webpack-plugin 在打包的时候会删除之前的打包目录
webpack-bundle-analyzer 在打包结束的时候,会启动启动一个服务在浏览器查看打包的大小和包含的内容等
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
插件的引用已经改了
复制代码
2.异步加载
首先是 code splitting(代码分割)
如果你不太熟悉这个功能,webpack 基本上可以帮助你把代码打包成多个chunk,当用户打开你的应用的时候,先会下载一个主bundle,然后当用户导航到一些页面包含了其他的逻辑和静态资源的使用,再按需加载这些chunk。但是要手动处理成这个效果非常的复杂,当然这样处理后可以很有效地减少用户的白屏时间,并且让移动端用户有更好的体验。webpack(或者其他解决方案)在这里扮演了一个很重要的角色,他可以在创建这些bundle的时候处理这些复杂的逻辑,并且在需要的时候再去下载他们。所以我们所需要做的就是将该功能合并到我们的应用程序中,这样用户就可以获得无缝的体验。
import React, { Suspense } from "react";
import { HashRouter as Router, Switch, Link, Route } from 'react-router-dom';
const HomeComponent = React.lazy(() => import(/* webpackChunkName: "HomeComponent" */ '../views/home'));
const ListComponent = React.lazy(() => import(/* webpackChunkName: "ListComponent" */ '../views/list'));
const Home = (props) => {
return (
<Suspense fallback={<div>加载中...</div>}>
<HomeComponent {...props} />
</Suspense>
)
}
const List = (props) => {
return (
<Suspense fallback={<div>加载中...</div>}>
<ListComponent {...props} />
</Suspense>
)
}
class AppRouter extends React.Component {
render() {
return (
<Router>
<div>
<ul>
<li><Link to="/home">home</Link></li>
<li><Link to="/list">blog</Link></li>
</ul>
{/* Switch只显示一个组件。加exact表示精确匹配/。如果不加exact,/xxx也会匹配/。 */}
<Switch>
{/* exact */}
<Route path="/home" component={Home} />
<Route exact path="/list" component={List} />
</Switch>
</div>
</Router>
)
}
}
export default AppRouter;
复制代码
3.css处理
1.npm install --save-dev mini-css-extract-plugin
webpack4需要自己使用压缩器,可以使用 optimize-css-assets-webpack-plugin 插件。 设置 optimization.minimizer 覆盖webpack默认提供的,确保也指定一个JS压缩器
MiniCssExtractPlugin 失效打包后还是在一起
经过排查const devMode = process.env.NODE_ENV !== 'production'; 这里的变量出来时undefined
所以我们要在package.json 里面配上 NODE_ENV=production
复制代码
因为uglifyjs不支持es6语法,所以用terser-webpack-plugin替代uglifyjs-webpack-plugin
terser-webpack-plugin安装:yarn add terser-webpack-plugin -D
使用: webpack.config.js
minimizer: [new TerserJSPlugin({
cache: true, // 是否缓存
paraller: true, // 是否并行打包
sourceMap: true
})],
复制代码
4.js处理
多线程打包:happypack
npm install happypack --save-dev
npm install os --save-dev
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
{
test: /\.(js|jsx)$/, // 一个匹配loaders所处理的文件的拓展名的正则表达式,这里用来匹配js和jsx文件(必须)
exclude: /node_modules/, // 屏蔽不需要处理的文件(文件夹)(可选)
use: [
{
loader: 'happypack/loader?id=babelLoader'
}
]
},
new happypack({
id: 'babelLoader',
use: [{
loader: 'babel-loader'
}],
//共享进程池
threadPool: happyThreadPool,
}),
复制代码
九、开发插件及开发规范
1.axios
npm install axios
复制代码
2.rematch
npm install @rematch/core --save
复制代码
十、问题
1.最近在安装使用webpack的copy-webpack-plugin 拷贝插件的时候,报了一些错误:
错误详见下面代码,没有粘贴完, 大概意思就是Copy Plugin的初始化对象不正确,查看了官网也没有看出所以然,最后在npm官网上找打了原因
new CopyWebpackPlugin([
{
patterns: [
{
from: resolve('/static'),
to: 'static'
}
]
}
])
但是和htmlplugin会有冲突 所以下载低版本的copy-webpack-plugin插件就好了
复制代码