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 相关文章推荐
JavaScript高级程序设计
Dec 29 Javascript
javascript入门·动态的时钟,显示完整的一些方法,新年倒计时
Oct 01 Javascript
filters.revealTrans.Transition使用方法小结
Aug 19 Javascript
Jquery中的CheckBox、RadioButton、DropDownList的取值赋值实现代码
Oct 12 Javascript
js css后面所带参数含义介绍
Aug 18 Javascript
jQuery中:selected选择器用法实例
Jan 04 Javascript
jQuery遍历json的方法(推荐)
Jun 12 Javascript
微信小程序 wx.uploadFile无法上传解决办法
Dec 14 Javascript
node.js学习之事件模块Events的使用示例
Sep 28 Javascript
玩转vue的slot内容分发
Sep 22 Javascript
对angularJs中controller控制器scope父子集作用域的实例讲解
Oct 08 Javascript
JavaScript实现alert弹框效果
Nov 19 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在字符串中查找另一个字符串
2008/11/19 PHP
php中防止伪造跨站请求的小招式
2011/09/02 PHP
解析csv数据导入mysql的方法
2013/07/01 PHP
PHP常见错误提示含义解释(实用!值得收藏)
2016/04/25 PHP
解放web程序员的输入验证
2006/10/06 Javascript
菜鸟学习JavaScript小实验之函数引用
2010/11/17 Javascript
Js冒泡事件详解及阻止示例
2014/03/21 Javascript
JavaScript获取table中某一列的值的方法
2014/05/06 Javascript
JavaScript实现防止网页被嵌入Frame框架的代码分享
2014/12/29 Javascript
详解javascript实现自定义事件
2016/01/19 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
2016/12/01 Javascript
Vue学习笔记进阶篇之vue-cli安装及介绍
2017/07/18 Javascript
js is_valid_filename验证文件名的函数
2017/07/19 Javascript
深入理解Vue.js源码之事件机制
2017/09/27 Javascript
解决Vue不能检测数组或对象变动的问题
2018/02/24 Javascript
vue项目移动端实现ip输入框问题
2019/03/19 Javascript
webpack 如何解析代码模块路径的实现
2019/09/04 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
Python全局变量操作详解
2015/04/14 Python
Python排序搜索基本算法之堆排序实例详解
2017/12/08 Python
python获取文件路径、文件名、后缀名的实例
2018/04/23 Python
Python绘制堆叠柱状图的实例
2019/07/09 Python
Django Admin设置应用程序及模型顺序方法详解
2020/04/01 Python
size?法国官网:英国伦敦的球鞋精品店
2020/03/15 全球购物
荷兰最大的鞋子、服装和运动折扣店:Bristol
2021/01/07 全球购物
社区党总支书记先进事迹材料
2014/01/24 职场文书
司机检讨书
2014/02/13 职场文书
酒店管理毕业生自我鉴定
2014/03/02 职场文书
毕业横幅标语
2014/10/08 职场文书
终止劳动合同证明书样本
2014/11/19 职场文书
校本培训个人总结
2015/02/28 职场文书
捐书活动倡议书
2015/04/27 职场文书
大学生活委员竞选稿
2015/11/21 职场文书
小学四年级作文之人物作文
2019/11/06 职场文书
mysql聚集索引、辅助索引、覆盖索引、联合索引的使用
2022/02/12 MySQL
Windows Server 2016 配置 IIS 的详细步骤
2022/04/28 Servers