create-react-app 修改为多入口编译的方法
需求和出发点
我们会有较多的小的单页应用,主要是一些简单的页面和活动之类。这些页面相互之间没有交集,但是会有一些可以共用的代码,资源、接口、组件啥的。
对此,我们想到了两种解决方案:
- react-router 路由方案;
- 同一个项目的多入口编译;
针对我们的业务需求,其实 react-router 方案会有两个小问题:
- 单个活动的修改,其实需要编译整个项目;
- 若是不做编译优化,整个项目的包会比较大,但其实没必要,当然这个可以通过 react-router 的按需加载来解决;
权衡之下,我们还是选择了第二个方案——改造项目成为多入口编译。
文件结构设计
改进后,整个项目的结构大体如下:
- project
- build
- config
- public
- scripts
- src
- api
- component
- site
- site1
- index.html
- index.js
- ...
- site2
- index.html
- index.js
- ...
- package.json
site 文件夹下的所有文件夹都是一个独立的项目,项目通用的代码、资源被抽离到更外层的文件夹内,如 api、component 等,文件夹内都会有自己的 index.html 和 index.js,这会作为该项目的 html 模板和入口文件。下面,我们看下是如何修改编译过程的。
修改入口和出口
编译需要指定编译的入口和输出的位置,在 create-react-app 本来生成的 code 中,只有单入口和单出口,但是其实 webpack 是支持多入口、多出口的。
入口修改
create-react-app 命令生成的 config 文件夹中,有个 paths.js 文件,这里面 export 了比较常用的路径。在这里,我对 src/site 文件夹内的文件夹进行了遍历,生成为对象。具体代码如下:
// all site paths
function allSitePath(source) {
const { lstatSync, readdirSync } = fs
const { join } = path
const result = {}
const isDirectory = source => lstatSync(source).isDirectory()
readdirSync(source).map(name => {
let path = join(resolveApp(source), name)
if (isDirectory(path)) result[name] = path
})
return result
}
module.exports = {
...
allSites: allSitePath('src/site'),
}
在 webpack.config.dev.js / webpack.config.prod.js 中找到 module.exports 的 entry 属性,将其修改为:
// 动态生成 entry
const entry = {}
Object.keys(paths.allSites).forEach(item => {
entry[item] = [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('react-error-overlay'),
paths.allSites[item]
]
})
module.exports = {
...
entry: entry,
...
}
出口修改
出口的修改分为两部分,一部分是 module.exports 的 output,添加 name 以使静态资源区分不同项目:
module.exports = {
...
output: {
path: paths.appBuild,
pathinfo: true,
filename: 'static/js/[name].bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
...
}
另一部分是 plugin 的修改,webpack 中,每个 HTML 文件的输出,其实是一个 HtmlWebpackPlugin,我们需要添加多个 HtmlWebpackPlugin,以求生成多个 HTML:
// 动态生成 plugins
const plugins = []
Object.keys(paths.allSites).forEach(item => {
plugins.push(new HtmlWebpackPlugin({
inject: true,
chunks: [item],
template: `${paths.allSites[item]}/index.html`,
filename: `${item}/index.html`,
}))
})
module.exports = {
...
plugins: [
...
].concat(plugins),
...
}
修改 webpack Dev Server 配置
上述配置做完后,理论就可以打包出多入口的版本;但使用npm start启动后,发现无论输入/index.html还是/admin.html,好像都是和原来/index.html显示一样的内容。甚至输入显然不存在的/xxxx.html,也显示为/index.html的内容。
这里,我们还需要修改 /config/webpackDevServer.config.js,做一些额外配置。
const rewrites = []
Object.keys(paths.allSites).forEach(item => {
rewrites.push({
from: new RegExp(`^\\/${item}/`, 'i'),
to: `/${item}/index.html`,
})
})
...
module.exports = function(proxy, allowedHost) {
return {
...
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
// 指明哪些路径映射到哪个html
rewrites: rewrites,
},
...
};
};
OK,到这里,整个改造就完成了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
react路由基础解读(Router、Link和Route)
这篇文章主要介绍了react路由基础解读(Router、Link和Route),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-07-07
react组件中的constructor和super知识点整理
这篇文章主要介绍了react组件中的constructor和super知识点整理,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-08-08
React合成事件及Test Utilities在Facebook内部进行测试
这篇文章主要介绍了React合成事件及Test Utilities在Facebook内部进行测试,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-12-12
一篇文章介绍redux、react-redux、redux-saga总结
这篇文章主要介绍了一篇文章介绍redux、react-redux、redux-saga总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2019-05-05
关于react-router/react-router-dom v4 history不能访问问题的解决
这篇文章主要给大家介绍了关于react-router/react-router-dom v4 history不能访问问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。2018-01-01
React+echarts (echarts-for-react) 实现中国地图及省份切换功能
这篇文章主要介绍了React+echarts (echarts-for-react) 画中国地图及省份切换,有足够的地图数据,可以点击到街道,示例我只出到市级,本文结合实例代码给大家介绍的非常详细需要的朋友可以参考下2022-11-11


最新评论