create-react-app 修改为多入口编译的方法


Posted in Javascript onAugust 01, 2018

需求和出发点

我们会有较多的小的单页应用,主要是一些简单的页面和活动之类。这些页面相互之间没有交集,但是会有一些可以共用的代码,资源、接口、组件啥的。

对此,我们想到了两种解决方案:

  • 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,到这里,整个改造就完成了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的15款幻灯片插件
Apr 10 Javascript
Jquery post传递数组方法实现思路及代码
Apr 28 Javascript
jquery iframe操作详细解析
Nov 20 Javascript
JS常见问题之为什么点击弹出的i总是最后一个
Jan 05 Javascript
Bootstrap树形控件使用方法详解
Jan 27 Javascript
zTree树形插件异步加载方法详解
Jun 14 Javascript
创建简单的node服务器实例(分享)
Jun 23 Javascript
vue 权限认证token的实现方法
Jul 17 Javascript
Vue文件配置全局变量的实例
Sep 06 Javascript
vscode中eslint插件的配置(prettier配置无效)
Sep 10 Javascript
js实现提交前对列表数据的增删改查
Jan 16 Javascript
vue-video-player实现实时视频播放方式(监控设备-rtmp流)
Aug 10 Javascript
Vue项目全局配置页面缓存之按需读取缓存的实现详解
Aug 01 #Javascript
JavaScript执行环境及作用域链实例分析
Aug 01 #Javascript
Vue.js 利用v-for中的index值实现隔行变色
Aug 01 #Javascript
echarts设置图例颜色和地图底色的方法实例
Aug 01 #Javascript
看看“疫苗查询”小程序有温度的代码
Jul 31 #Javascript
Vue父子组件双向绑定传值的实现方法
Jul 31 #Javascript
react中实现搜索结果中关键词高亮显示
Jul 31 #Javascript
You might like
eWebEditor v3.8 商业完整版 (PHP)
2006/12/06 PHP
php实现utf-8和GB2312编码相互转换函数代码
2013/02/07 PHP
PHP preg_match实现正则表达式匹配功能【输出是否匹配及匹配值】
2017/07/19 PHP
PHP工厂模式、单例模式与注册树模式实例详解
2019/06/03 PHP
JavaScript的面向对象(一)
2006/11/09 Javascript
javascript innerHTML使用分析
2010/12/03 Javascript
JS实现div内部的文字或图片自动循环滚动代码
2013/04/19 Javascript
js实现将选中值累加到文本框的方法
2015/08/12 Javascript
js实现选中复选框文字变色的方法
2015/08/14 Javascript
基于jquery实现一个滚动的分步注册向导-附源码
2015/08/26 Javascript
DIV随滚动条滚动而滚动的实现代码【推荐】
2016/04/12 Javascript
AngularJS实现tab选项卡的方法详解
2017/07/05 Javascript
在vue中通过axios异步使用echarts的方法
2018/01/13 Javascript
nodejs初始化init的示例代码
2018/10/10 NodeJs
详解ES6 Promise对象then方法链式调用
2018/10/20 Javascript
jQuery实现的卷帘门滑入滑出效果【案例】
2019/02/18 jQuery
详解vue移动端项目代码拆分记录
2019/03/15 Javascript
vue不操作dom实现图片轮播的示例代码
2019/12/18 Javascript
[48:23]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第一局
2016/03/05 DOTA
400多行Python代码实现了一个FTP服务器
2012/05/10 Python
python实现DES加密解密方法实例详解
2015/06/30 Python
python基于event实现线程间通信控制
2020/01/13 Python
Python使用plt.boxplot() 参数绘制箱线图
2020/06/04 Python
pycharm 2020.2.4 pip install Flask 报错 Error:Non-zero exit code的问题
2020/12/04 Python
Python实现Appium端口检测与释放的实现
2020/12/31 Python
仿CSDN Blog返回页面顶部功能实现原理及代码
2013/06/30 HTML / CSS
国外平面设计第一市场:99designs
2016/10/25 全球购物
什么是用户模式(User Mode)与内核模式(Kernel Mode) ?
2014/07/21 面试题
销售实习自我鉴定
2013/12/07 职场文书
项目开发计划书
2014/01/09 职场文书
微观物理专业自荐信
2014/01/26 职场文书
幼儿园消防演练方案
2014/02/13 职场文书
电子专业求职信
2014/06/19 职场文书
《吃水不忘挖井人》教学反思
2016/02/22 职场文书
2016年社区“我们的节日·中秋节”活动总结
2016/04/05 职场文书
Redis三种集群模式详解
2021/10/05 Redis