# dora + atool-build 升级到 roadhog
# 背景
公司的一个项目做的时间比较久,用的是基于 dora+atool-build
的开发和部署环境,在开发的过程中碰到了如下几个问题,一是热更新有时会不生效,导致修改文件后,需要再手动重启一下本地服务,影响了开发效率。其次是 dora
和 atool-build
已是比较老的版本,作者现在已停止维护,并且也给出了升级到 roadhog
的建议。本文记录升级到 roadhog
的步骤及遇到的问题。
# 目标
此次升级的主要目标如下:
- 将项目的开发和打包环境切换到
roadhog
,解决当前遇到的热更新不生效的问题 - 兼容现有的打包方式,打包后的结果跟现在保持一致,包括打包后的js文件和css文件名保持现有的带hash的方式、公共文件的提取、异步加载等方式
- 兼容现有的数据mock方式,现在mock文件写的比较多,升级后仍要保持现有的mock文件有效
# 步骤
# 基本配置
1、删掉package.json中的 dora 和 atool-build 相关依赖:
{
// dora
"dora": "^0.4.3",
"dora-plugin-proxy": "^0.8.2",
"dora-plugin-webpack": "^0.8.1",
"dora-plugin-webpack-hmr": "^0.2.1",
// atool
"atool-build": "^0.8.0",
"atool-test-mocha": "^0.1.5",
}
2、安装 roadhog,这里使用版本是0.6.1,后面会提为什么要用这个版本
npm i -D roadhog@0.6.1
3、修改脚本
{
scripts: {
"start": "roadhog server",
"roadhog-build": "roadhog build",
}
}
4、新增 .roadhogrc 配置文件
{
"entry": "src/index.js",
"disableCSSModules": true,
"less": true,
"publicPath": "/",
"outputPath": "build",
"autoprefixer": null,
"proxy": null,
"devtool": "eval",
"extraBabelPlugins": [
"transform-runtime",
"transform-decorators-legacy",
["import", { "libraryName": "antd", "style": "css" }]
],
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr"
]
}
}
}
这一步可参考文档:
然后安装这几个依赖:
# 开发依赖
npm i babel-plugin-transform-runtime@6.23.0 babel-plugin-import@1.13.3 babel-plugin-dva-hmr@0.4.0 babel-plugin-transform-decorators-legacy@1.3.5 --save-dev
# 生产依赖
npm i babel-runtime@6.26.0 --save
插件解析:
- babel-plugin-transform-runtime:编译阶段代码转换,转译语法和api。babel-plugin-transform-runtime作用 (opens new window)
- babel-plugin-import:antd 组件按需引入
- babel-plugin-transform-decorators-legacy: 支持装饰器写法
- babel-runtime:babel-plugin-transform-runtime转译过程中需要使用一些辅助函数,babel-runtime就是提供这些helper函数。运行阶段引入的对相关api(includs)或新语法(class、promise、generator等)的转换。babel-runtime作用 (opens new window)
5、新建public/index.html 文件夹,把src/index.ejs 内容复制过来,同时需要在index.html中添加如下内容:
<script src="index.js"></script>
这是由于.roadhog默认会打包出index.js文件,所以需要在html文件中手动引入(后面会使用webpack-html-plugin自动将打包的文件插入到html文件中,不需要手动引入)。
6、使用less
项目中使用了less变量配置了自定义主题,覆盖了antd的默认主题,所以需要在.roadhog做下需改:
- 把 disableCSSModules 设置为true,关闭cssModules
- style属性设置为true,加载antd的less样式
{
"disableCSSModules": true // 关闭cssModules,否则全局样式不生效
"extraBabelPlugins": [
"transform-runtime",
["import", { "libraryName": "antd", "style": "true" }] // true 表示使用antd的less文件,这样自定义主题才生效
],
}
7、修改字体引入
去掉 theme.less 文件中的 @icon-url : "/src/static/fonts/ux/iconfont"
变量覆盖,由于升级后导致antd中的一些小字体无法显示(比如menu的箭头)
删除后,字体加载的是aliyun地址的字体:
项目中使用的antd的版本是 2.x.x
,字体需要从 aliyun
上下载,但是在 3.x.x
版本中不存在这个问题,也就是字体直接打包到了antd中
但是如果您觉得从aliyun上下载字体不方向,必须得从本地加载,实际上也是可以配置的:
注释掉 theme.less 的这行代码;
是把 src/static/fonts 文件 存放到 public文件夹中
修改.roadhogrc,添加如下内容:
"theme": {
"@icon-url": "'/fonts/ux/iconfont'"
},
需要注意的是,双引号中一定要有单引号覆盖 @icon-url
变量,参考fix icon in package theme (opens new window)
8、安装less插件
npm i -D less-loader@2.2.3 less@2.7.3
但是呢坑总是无处不在的,如果安装less的最新的3.x.x版本,启动项目可能会遇到这个问题:src/index.less中 无法识别 '~antd/dist/antd.less'
此时需要把less-loader版本降低,安装 less@2.7.3 这个版本
参考:解决 dva @import "./themes/default"; 无法读取问题 (opens new window)
9、修改webapck配置文件名
roadhog默认会读取项目中的webpack.config.js配置文件,此时我们暂时不用到webpack配置文件,所以暂时先把配置文件改成webpack.config1.js这个名,先让项目能跑起来。
通过👆的配置,没有意外的话,重新启动一下项目应该能跑起来了:
npm i
npm run start
# 配置mock
1、添加配置文件,新建.roadhogrc.mock.js 文件,并把之前的proxy.mock.js文件复制过来, 然后删除proxy.mock.js文件。在.roadhogrc.mock.js 中添加如下内容:
/**
* mock 写法可以使用当前这种方式
* 也可以使用加上请求方式:
* "POST /api/athena/monthCards/showRule/edit": "./mock/DisplayOrderConfigV2/detail.json",
* "GET /api/athena/monthCards/showRule/edit": "./mock/DisplayOrderConfigV2/detail.json",
*/
module.exports = require('./tools/mock_data')(proxyPath);
2、由于新的mock方法不支持直接填写路径名称,并且需要在mock的url前添加请求方法如GET、POST,所以添加了一个兼容方法,在/tools/mock_data.js中:
let fs = require("fs");
let path = require("path");
module.exports = function (proxyPath) {
const mock = {};
Object.keys(proxyPath).forEach((key) => {
let filePath = proxyPath[key];
if(typeof filePath !== "string") {
mock[key] = filePath;
return;
}
let targetPath = path.join(__dirname, "../" + filePath);
if (fs.existsSync(targetPath)) {
let result = require(targetPath);
if(key.indexOf('GET') > -1 || key.indexOf('POST') > -1){
mock[key] = result;
} else {
mock["GET " + key] = result;
mock["POST " + key] = result;
}
} else {
console.log("mock文件地址" + targetPath + "不存在,请检查");
}
});
return mock;
};
# 自定义配置
以上的过程是使用了roadhog的默认打包配置,但是在我们的项目中有一些自定义的配置,比如
- 打包文件名添加hash,roadhog默认打包出的文件没有hash名称
- 公共文件提取,css文件的提取
- 配置插件,自动生成html文件
这些通过配置webpack.config.js文件来实现
# 配置html-webpack-plugin
1、安装
npm i -D html-webpack-plugin@2.29.0 html-loader@0.5.5
2、在webpack.config.js中添加如下修改:
module.exports = function(webpackConfig){
...
// roadhog 默认使用 file-loader 读取html文件,读取的结果为二进制文件
// 所以需要修改为使用 html-loader 读取
webpackConfig.module.loaders.forEach(loader => {
if(loader.test && loader.test.toString().indexOf('html') > -1) {
loader.loader = 'html'
}
})
...
webpackConfig.plugins.push(new HtmlWebpackPlugin({
...
// 注意这里使用的是html文件,需要把index.ejs 改为 index.html。为什么不用ejs文件?
// 使用ejs文件会有相关bug
template: 'src/index.html',
}))
}
配置这个折腾了好一阵,参考添加html打包插件 (opens new window)
# 配置noParser
由于系统引入了jszip.js这个库,在编译时候会有相关warnning,加上下面这行可解决:
webpackConfig.module.noParse = [/jszip.js$/]
参考:jszip warning in console (opens new window)
# 配置common-chunk-plugin
1、安装
之前的webpack是从atool-build中引入的,把atool-build删除后,需要重新安装一下wepack
npm i -D webpack@1.14.0
+ const webpack = require('webpack')
- const webpack = require('atool-build/lib/webpack')
# 配置开发环境的文件名
此时,开发环境打包出的入口文件名称为index.js,在开发环境下的热更新是可以生效的,但是有个诡异的问题是,修改model中的文件,发现并没有生效,手动刷新也不行,只能重新启动一下,解决这个问题尝试了如下方法:
1、让 roadhog
不走 webpack.config.js
文件,发现修改 model
文件是可以生效的,这说明这跟我们的 webpack.config.js
的配置有关
2、猜想这可能跟 model
的动态加载有关,尝试添加如下配置可生效:
if (env === 'development') {
webpackConfig.output.filename = '[name].[hash].js'
}
这样打包出的 index.js
文件名就会加上hash,每次需改 model
后即可生效,不过需要自己手动刷新一下。手动刷新的步骤在不使用webpack.config.js中也是需要的。
# 生产环境提取css文件
提取css文件需要使用到 extract-text-webpack-plugin
这个插件
现在打包出来的js文件都是带上了hash值的,唯有一个css文件是不带hash的,在配置文件中明明有加上提取的css文件名,但是并没有生效:
webpackConfig.plugins.push(new ExtractTextPlugin('[name].[contenthash].css', { allChunks: true }))
暂时还不知添加插件的方法不生效的原因,猜测这个可能是 roadhog
当前版本的一个问题。
既然覆盖没有效果,只能修改默认的配置了,直接修改默认的配置发现是可行的,添加如下修改:
webpackConfig.plugins[3].filename = '[name].[contenthash].css'
webpackConfig.plugins[3].options = { allChunks: true }
无法加上hash值的原因 (opens new window)
# 修改脚本
1、此时,修改对之前的启动、打包、上传脚本做如下修改
{
"start": "node bin/start.js && roadhog server",
"roadhog-build": "roadhog build",
"build": "roadhog build && npm run stark",
}
2、修改start.js
这两个函数不需要了,可以注释了:
//function openBrowser() {
...
//}
//function startDora() {
...
//}
3、修改fix_path_new
升级后 不存在index.css文件,这里的fix不需要了
//var htmlFile = dist + '/index.html'
//var htmlFileContent = fs.readFileSync(htmlFile, 'utf-8')
//fs.writeFileSync(htmlFile, (function(text) {
....
//})(htmlFileContent), 'utf-8')
# 遇到的问题
迁移过程中遇到的一些比较棘手的问题及解决方法:
1、src/index.less
中无法识别 '~antd/dist/antd.less'
参考解决 dva @import "./themes/default"; 无法读取问题 (opens new window)
2、引入的全局样式没生效
index.js
中引入的 import './index.less'
没有生效
原因是在roadhog中默认开启了 cssModule
,在 .roadhogrc
中关掉即可
3、 使用 dva
高版本带来的问题
- react-router不兼容问题
- 和项目中一些依赖版本不兼容,导致开发和打包时出现各种奇怪的问题
# 总结
# 迁移结果
基于以上的配置主要实现了如下几个目标:
- 修复了热更新不生效的问题,提升开发体验
- 不改变现有的开发方式,没有破坏性升级,保持原有的开发方式,包括数据mock等。
- 基本还原了升级前的打包效果,包括打包文件加hash、公共文件提取、异步加载等。
# 收获了什么
之前没有在正式项目中做底层的升级,在这次升级的过程中还是遇到了一些相对棘手的问题,整体难度不大,也得到了一些收获:
- 整体规划。在升级之前先做充分的调研,确定要修改的内容有哪些。然后再分步骤进行,比如在此次升级过程中,先沿用了roadhog的默认配置,让项目先能跑起来。然后再修改mock、增加自定义的打包配置,最后再修改脚本。
- 一定要谷歌。过程中肯定会遇到很多奇怪的兼容问题,此时最好的办法是通过goolgle在github或stackoverflow上寻找答案
- 深入源码。在解决提取css的过程中,添加
ExtractTextPlugin
并没有生效,并且尝试了很多办法没有解决,此时只能去看roadhog的源码,看下它里面是如何配置的。然后在源码中通过添加插件的方式可以解决问题,但是在配置文件中添加就无法生效。像这样的迷之bug只能在源码中才能定位问题。 - babel及相关插件。加深了对babel相关插件的理解,比如
babel-transform-runtime
、babel-runtime
等的使用及区别。 - webpack。通过修改相关配置,webpack的相关模块的配置有更多认识,比如hash、contenthash、chunkhash这些区别,webpack中的module、chunk、bundle这些概念的理解
参考资料
- manifest
- hash
- 插件