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 相关文章推荐
js类中的公有变量和私有变量
Jul 24 Javascript
js浮点数保留两位小数点示例代码(四舍五入)
Dec 26 Javascript
js实现的标题栏新消息闪烁提示效果
Jun 06 Javascript
node.js中的emitter.emit方法使用说明
Dec 10 Javascript
Backbone.js 0.9.2 源码注释中文翻译版
Jun 25 Javascript
基于jquery实现ajax无刷新评论
Aug 19 Javascript
JS 动态加载js文件和css文件 同步/异步的两种简单方式
Sep 23 Javascript
vue2滚动条加载更多数据实现代码
Jan 10 Javascript
原生JavaScript实现todolist功能
Mar 02 Javascript
一百行JS代码实现一个校验工具
Apr 30 Javascript
基于iview的router常用控制方式
May 30 Javascript
uni-app微信小程序登录并使用vuex存储登录状态的思路详解
Nov 04 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
PHP开发中常用的8个小技巧
2008/08/27 PHP
了解Joomla 这款来自国外的php网站管理系统
2010/03/11 PHP
PHP得到某段时间区间的时间戳 php定时任务
2012/04/12 PHP
浅析php中抽象类和接口的概念以及区别
2013/06/27 PHP
php检测useragent版本示例
2014/03/24 PHP
PHP通过插入mysql数据来实现多机互锁实例
2014/11/05 PHP
PHP连接MYSQL数据库的3种常用方法
2017/02/27 PHP
JS JSON对象转为字符串的简单实现方法
2013/11/18 Javascript
JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
2014/08/16 Javascript
$.extend 的一个小问题
2015/06/18 Javascript
浅谈javascript中onbeforeunload与onunload事件
2015/12/10 Javascript
JS实现拖动滚动条评分的效果代码分享
2016/09/29 Javascript
angularJs关于指令的一些冷门属性详解
2016/10/24 Javascript
JavaScript面试题(指针、帽子和女朋友)
2016/11/23 Javascript
javascript实现简单的可随机变色网页计算器示例
2016/12/30 Javascript
vue安装和使用scss及sass与scss的区别详解
2018/10/15 Javascript
vuedraggable+element ui实现页面控件拖拽排序效果
2020/07/29 Javascript
layui插件表单验证提交触发提交的例子
2019/09/09 Javascript
vue项目初始化到登录login页面的示例
2019/10/31 Javascript
原生js实现下拉选项卡
2019/11/27 Javascript
vue 解决data中定义图片相对路径页面不显示的问题
2020/08/13 Javascript
python实现的文件夹清理程序分享
2014/11/22 Python
Python找出9个连续的空闲端口
2016/02/01 Python
python xml.etree.ElementTree遍历xml所有节点实例详解
2016/12/04 Python
在python中将list分段并保存为array类型的方法
2019/07/15 Python
简单了解python中的f.b.u.r函数
2019/11/02 Python
python中p-value的实现方式
2019/12/16 Python
python+adb命令实现自动刷视频脚本案例
2020/04/23 Python
用HTML5.0制作网页的教程
2010/05/30 HTML / CSS
英国领先的酒杯和水晶玻璃器皿制造商:Dartington Crystal
2019/06/23 全球购物
电大自我鉴定范文
2013/10/01 职场文书
旅游业大学生创业计划书
2014/01/31 职场文书
应届生求职自荐信
2014/07/04 职场文书
班级团队活动方案
2014/08/14 职场文书
2014年学校财务工作总结
2014/12/06 职场文书
2016重阳节红领巾广播稿
2015/12/18 职场文书