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 ajax服务器端与客户端通信的代码
Mar 28 Javascript
基于jquery的使ListNav兼容中文首字拼音排序的实现代码
Jul 10 Javascript
JavaScript中constructor()方法的使用简介
Jun 05 Javascript
jQuery跨域问题解决方案
Aug 03 Javascript
JavaScript实现算术平方根算法-代码超简单
Sep 11 Javascript
JavaScript之RegExp_动力节点Java学院整理
Jun 29 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
Jul 21 Javascript
提升页面加载速度的插件InstantClick
Sep 12 Javascript
详解Axios 如何取消已发送的请求
Oct 20 Javascript
详解JS实现系统登录页的登录和验证
Apr 29 Javascript
Vue在chrome44偶现点击子元素事件无法冒泡的解决方法
Dec 15 Javascript
简单了解vue 插值表达式Mustache
Jul 22 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
PHP5 面向对象程序设计
2008/02/13 PHP
php处理复杂xml数据示例
2016/07/11 PHP
php中使用websocket详解
2016/09/23 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
2018/09/28 PHP
监控 url fragment变化的js代码
2010/04/19 Javascript
Jquery.TreeView结合ASP.Net和数据库生成菜单导航条
2010/08/27 Javascript
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
js控制淡入淡出示例代码
2013/11/12 Javascript
javascript实现ecshop搜索框键盘上下键切换控制
2015/03/18 Javascript
JavaScript实现的简单烟花特效代码
2015/10/20 Javascript
表单中单选框添加选项和移除选项
2016/07/04 Javascript
JavaScript组合模式学习要点
2016/08/26 Javascript
AngularJS实现根据不同条件显示不同控件
2017/04/20 Javascript
JavaScript基于replace+正则实现ES6的字符串模版功能
2017/04/25 Javascript
jQuery UI Draggable + Sortable 结合使用(实例讲解)
2017/09/07 jQuery
nodejs简单访问及操作mysql数据库的方法示例
2018/03/15 NodeJs
微信小程序在ios下Echarts图表不能滑动的问题解决
2019/07/10 Javascript
[01:13:01]2018DOTA2亚洲邀请赛 4.4 淘汰赛 TNC vs VG 第三场
2018/04/05 DOTA
[53:15]Mineski vs iG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python multiprocessing模块中的Pipe管道使用实例
2015/04/11 Python
Python os模块学习笔记
2015/06/21 Python
用python实现简单EXCEL数据统计的实例
2017/01/24 Python
Python编程对列表中字典元素进行排序的方法详解
2017/05/26 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
2018/06/01 Python
python实现事件驱动
2018/11/21 Python
Pycharm小白级简单使用教程
2020/01/08 Python
python同时遍历两个list用法说明
2020/05/02 Python
Python下使用Trackbar实现绘图板
2020/10/27 Python
Lookfantastic日本官网:英国知名护肤、化妆品和头发护理购物网站
2018/04/21 全球购物
巴西儿童时尚购物网站:Dinda
2019/08/14 全球购物
俄罗斯女装店:12storeez
2019/10/25 全球购物
P D PAOLA法国官网:西班牙著名的珠宝首饰品牌
2020/02/15 全球购物
高中生自我评语大全
2014/01/19 职场文书
法院授权委托书范文
2014/08/02 职场文书
Python+Pillow+Pytesseract实现验证码识别
2022/05/11 Python
ORACLE中dbms_output.put_line输出问题的解决过程
2022/06/28 Oracle