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实现左右div自适应高度完全相同的代码
Aug 09 Javascript
js字符串日期yyyy-MM-dd转化为date示例代码
Mar 06 Javascript
jQuery实现菜单感应鼠标滑动动画效果的方法
Feb 28 Javascript
基于JS实现EOS隐藏错误提示层代码
Apr 25 Javascript
原生js仿jquery一些常用方法(必看篇)
Sep 20 Javascript
基于VUE选择上传图片并页面显示(图片可删除)
May 25 Javascript
vue实现长图垂直居上 vue实现短图垂直居中
Oct 18 Javascript
Vue.js 点击按钮显示/隐藏内容的实例代码
Feb 08 Javascript
js统计页面上每个标签的数量实例代码
May 29 Javascript
详解如何在vue-cli中使用vuex
Aug 07 Javascript
详解小程序循环require之坑
Mar 08 Javascript
jquery多级树形下拉菜单的实例代码
Jul 09 jQuery
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+mysql事务rollback&commit示例
2010/02/08 PHP
php smarty truncate UTF8乱码问题解决办法
2014/06/13 PHP
PHP动态页生成静态页的3种常用方法
2014/11/13 PHP
php使用ob_flush不能每隔一秒输出原理分析
2015/06/02 PHP
PHP会话处理的10个函数
2015/08/11 PHP
Laravel-添加后台模板AdminLte的实现方法
2019/10/08 PHP
PHP实现15位身份证号转18位的方法分析
2019/10/16 PHP
飞鱼(shqlsl) javascript作品集
2006/12/16 Javascript
基于jquery的代码显示区域自动拉长效果
2011/12/07 Javascript
nodejs的require模块(文件模块/核心模块)及路径介绍
2013/01/14 NodeJs
jquery实现textarea 高度自适应
2015/03/11 Javascript
jquery中添加属性和删除属性
2015/06/03 Javascript
jQuery+css实现的切换图片功能代码
2016/01/27 Javascript
jqGrid用法汇总(全经典)
2016/06/28 Javascript
jQuery实现复选框的全选和反选
2017/02/02 Javascript
Electron-vue脚手架改造vue项目的方法
2018/10/22 Javascript
详解JavaScript中typeof与instanceof用法
2018/10/24 Javascript
vue+element+Java实现批量删除功能
2019/04/08 Javascript
layer.confirm点击第一个按钮关闭弹出框的方法
2019/09/09 Javascript
Vue调用后端java接口的实例代码
2019/10/28 Javascript
Nest.js环境变量配置与序列化详解
2021/02/21 Javascript
[02:19]2018年度DOTA2最佳核心位选手-完美盛典
2018/12/17 DOTA
Python的Django框架中模板碎片缓存简介
2015/07/24 Python
Python3.6正式版新特性预览
2016/12/15 Python
Python文本统计功能之西游记用字统计操作示例
2018/05/07 Python
python安装scipy的方法步骤
2019/06/26 Python
python requests抓取one推送文字和图片代码实例
2019/11/04 Python
python使用html2text库实现从HTML转markdown的方法详解
2020/02/21 Python
Python urllib3软件包的使用说明
2020/11/18 Python
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
2012/12/13 HTML / CSS
Lulu & Georgia官方网站:购买地毯、家具、抱枕、壁纸、床上用品等
2018/03/19 全球购物
实习销售业务员自我鉴定
2013/09/21 职场文书
公司财务会计主管应聘求职信
2014/09/26 职场文书
群众路线领导班子四风对照检查材料
2014/09/27 职场文书
优秀共产党员主要事迹材料
2015/11/05 职场文书
入团申请书格式
2019/06/20 职场文书