如今作的项目仍是基于早期的ant-design-pro
那套东西,技术栈是 react + antd + dva + roadhog。随着项目的迭代,不知从什么时候起,发现项目打包很慢,每次jenkins
上部署都要五、6分钟的样子。正好最近项目需求较少,正好有时间能够捣鼓一下这个打包慢的问题。javascript
去roadhog的github下面搜索issues,发现有好多人和我遇到一样的问题,解决方法大概就是把roadhog换成原汁原味的webpack4,因而我就开始着手改造了。css
删除roadhog相关依赖html
"roadhog": "^2.5.0-beta.1",
"roadhog-api-doc": "^1.0.3",
复制代码
在devDependencies添加webpack4须要用到相关依赖java
"webpack": "^4.8.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.4"
复制代码
我完整的devDependencies是这样的node
"@hot-loader/react-dom": "^16.8.6",
"@webassemblyjs/ast": "^1.3.1",
"@webassemblyjs/wasm-edit": "^1.3.1",
"address": "^1.0.3",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4",
"babel-plugin-import": "^1.7.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-remove-console": "^6.9.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-runtime": "^6.26.0",
"body-parser": "^1.18.3",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.1",
"cross-env": "^5.1.1",
"cross-port-killer": "^1.0.1",
"css-hot-loader": "^1.4.4",
"css-loader": "^0.28.11",
"cssnano": "^3.10.0",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-compat": "^2.2.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"estraverse": "^4.2.0",
"file-loader": "^1.1.11",
"happypack": "^5.0.0-beta.4",
"hard-source-webpack-plugin": "^0.8.0",
"html-webpack-plugin": "^4.0.0-beta.5",
"husky": "^1.0.0-rc.4",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"mini-css-extract-plugin": "^0.4.1",
"mockjs": "^1.0.1-beta3",
"optimize-css-assets-webpack-plugin": "^4.0.1",
"pro-download": "^1.0.1",
"react-hot-loader": "^4.8.4",
"redbox-react": "^1.5.0",
"redux-devtools": "^3.4.1",
"redux-devtools-dock-monitor": "^1.1.3",
"redux-devtools-log-monitor": "^1.4.0",
"regenerator-runtime": "^0.11.1",
"sass-loader": "^7.0.1",
"serve-index": "^1.9.1",
"style-loader": "^0.21.0",
"stylelint": "^9.2.0",
"stylelint-config-standard": "^18.2.0",
"type-is": "^1.6.15",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "^1.0.1",
"webpack": "^4.8.1",
"webpack-bundle-analyzer": "^2.11.2",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.4"
复制代码
修改scripts
里的启动、打包命令react
本地启动命令:webpack
"start": "cross-env ESLINT=none webpack-dev-server --config=webpack.config.development.js --mode development"
复制代码
打包命令:git
"build": "cross-env ESLINT=none webpack --config=webpack.config.production.js --mode production"
复制代码
刚刚应该有注意到我上面的脚本里有用到webpack.config.development.js
和webpack.config.production.js
这两个文件。github
这两个文件是须要咱们手动新增到根目录下面的。web
webpack.config.development.js
是用来给本地启动用的,下面是这个文件里的完整内容const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const theme = require('./src/theme');
module.exports = {
entry: path.resolve(__dirname, 'src', 'index.js'),
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
host: 'localhost', // 主机地址
port: 8000, // 端口号
open: true,
inline: true,
openPage: 'ioc/#/user/login',
hot: true,
publicPath: '/ioc/',
historyApiFallback: true,
overlay: {
errors: true,
},
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
publicPath: './',
chunkFilename: '[name].async.js',
},
resolve: {
alias: {
src: path.resolve(__dirname, 'src/'),
},
},
stats: {
children: false,
warningsFilter: warn => warn.indexOf('Conflicting order between:') > -1,
},
module: {
rules: [
{
test: /\.js$/,
include: [path.resolve(__dirname, 'src')],
loader: 'babel-loader?cacheDirectory',
},
{
test: /\.css$/,
use: [
'css-hot-loader',
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
],
},
{
test: /\.less$/,
use: [
'css-hot-loader',
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[name]_[local]-[hash:base64:5]',
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
modifyVars: theme,
},
},
],
exclude: /node_modules/,
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
modifyVars: theme,
},
},
],
exclude: /src/,
},
{
test: /\.(png|svg|jpg|gif|ttf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
outputPath: './assets/',
},
},
],
},
],
},
node: {
fs: 'empty',
module: 'empty',
},
devtool: false,
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.(css|less)/,
chunks: 'all',
enforce: true,
},
},
},
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'index.ejs'), // 模板
filename: 'index.html',
hash: true, // 防止缓存
}),
new CleanWebpackPlugin(['dist']),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, 'public'),
},
]),
new webpack.HotModuleReplacementPlugin(),
],
};
复制代码
webpack.config.production.js
是用来给打包用的,下面是这个文件里的完整内容const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HappyPack = require('happypack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
const theme = require('./src/theme');
module.exports = {
entry: path.resolve(__dirname, 'src', 'index.js'),
output: {
filename: '[name].[chunkhash:8].js',
path: path.resolve(__dirname, 'dist'),
publicPath: './',
chunkFilename: '[name].[chunkhash:8].async.js',
},
resolve: {
alias: {
src: path.resolve(__dirname, 'src/'),
},
},
module: {
rules: [
{
test: /\.js$/,
include: [path.resolve(__dirname, 'src')],
use: ['happypack/loader?id=babel'],
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[name]_[local]-[hash:base64:5]',
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
modifyVars: theme,
},
},
],
exclude: /node_modules/,
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
modifyVars: theme,
},
},
],
exclude: /src/,
},
{
test: /\.(png|svg|jpg|gif|ttf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
outputPath: './assets/',
},
},
],
},
],
},
stats: {
children: false,
warningsFilter: warn => warn.indexOf('Conflicting order between:') > -1,
},
node: {
fs: 'empty',
module: 'empty',
},
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.(css|less)/,
chunks: 'all',
enforce: true,
},
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
},
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
},
},
runtimeChunk: true,
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'index.ejs'), // 模板
filename: 'index.html',
hash: true, // 防止缓存
}),
new CleanWebpackPlugin(['dist']),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, 'public'),
},
]),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true,
}),
new HappyPack({
id: 'babel',
loaders: ['babel-loader?cacheDirectory'],
threadPool: happyThreadPool,
}),
new webpack.HashedModuleIdsPlugin(),
],
};
复制代码
别小看上面这段配置,这但是我百度了一些webpack的配置模板,而后再去研究webpack4的接口文档,再结合咱们的这个实际项目,不断调试报错,花了大半天时间搞出来的。
能够看到development
的配置文件比production
多了devServer
和hmr
相关的配置,可是production
的比development
多了代码压缩、以及HappyPack
相关配置。因此我以为分红两个配置文件仍是颇有必要的,这样就能够根据本地调试和线上打包具体需求的差别修改不一样的配置文件。
找到根目录下的.babelrc文件,稍做修改
{
"presets": ["env", "react", "stage-0"],
"plugins": [
"dva-hmr",
"transform-decorators-legacy",
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }],
"transform-class-properties",
"transform-runtime"
],
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
复制代码
主要是添加了dva-hmr
这个热更新插件。
删除node_modules
。因为 package.json
中依赖改的比较多,因此建议先把原来项目中的node_modules
文件夹删掉,以避免形成没必要要的冲突。
安装依赖
npm i
复制代码
或者
cnpm i
复制代码
本地启动
npm start
复制代码
不出意外的话,本地应该能够启动成功,而且会自动打开浏览器页面
打包
npm run build
复制代码
本地启动成功,再试着打一个线上环境的包,根目录下会多出一个dist
文件夹,里面就是打包好的文件。
打包时间明显缩短了,这一点无论是本地打包或者jenkins
打包,都明显提高。
迁移以前时间
迁移以后时间
node
版本最好升级到v8.11.1
以上。一开始我本地能够打包成功,可是jenkens
上打包失败了,看了一下log
npm ERR! node v6.16.0
npm ERR! npm v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! green-town-ioc@0.3.0 build: `cross-env ESLINT=none webpack --config=webpack.config.development.js --mode development`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the green-town-ioc@0.3.0 build script 'cross-env ESLINT=none webpack --config=webpack.config.development.js --mode development'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
复制代码
发现我本地电脑用的node
是v8.11.1
,可是jenkins
服务器的版本是v6.16.0
的,而后我让咱们的运维童鞋把jenkins
上的node
版本升级了一下,就打包成功了。
关于HMR
,用的是dva
提供的babel插件dva-hmr
,这样本地修改代码,页面就会自动刷新了。一开始我dev
配置把sourceMap
功能打开了,而后每次修改完代码,就会隔好久页面才能刷新,后来直接去掉了,热更新就快了不少
DllReferencePlugin
插件。hmr
换成react-hot-loader
,这样本地开发更新了代码后就能够保存react组件状态。当时也试过用它,可是始终没有成功,因此被迫无奈用了dva-hmr
。有迁移想法的小伙伴欢迎在评论区交流。