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 28 Javascript
jQuery 1.5 源码解读 面向中高阶JSER
Apr 05 Javascript
基于jquery实现的文字淡入淡出效果
Nov 14 Javascript
浅析JavaScript基本类型与引用类型
May 28 Javascript
setTimeout内不支持jquery的选择器的解决方案
Apr 28 Javascript
javascript绘制漂亮的心型线效果完整实例
Feb 02 Javascript
jQuery Mobile框架中的表单组件基础使用教程
May 17 Javascript
easyui combobox开启搜索自动完成功能的实例代码
Nov 08 Javascript
js实现省份下拉菜单效果
Feb 15 Javascript
js实现简单的获取验证码按钮效果
Mar 03 Javascript
vue中的inject学习教程
Apr 24 Javascript
Vue中插槽slot的使用方法与应用场景详析
Jun 08 Vue.js
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的curl实现get和post的代码
2008/08/23 PHP
PHP漏洞全解(详细介绍)
2012/11/13 PHP
php连接mssql数据库的几种方法
2013/02/21 PHP
利用curl 多线程 模拟 并发的详解
2013/06/14 PHP
php中time()与$_SERVER[REQUEST_TIME]用法区别
2014/11/19 PHP
php查询内存信息操作示例
2019/05/09 PHP
fckeditor 获取文本框值的实现代码
2009/02/09 Javascript
基于jquery的表头固定的若干方法
2011/01/27 Javascript
Mac地址验证的javascript代码
2013/11/09 Javascript
JavaScript中使用Callback控制流程介绍
2015/03/16 Javascript
jQuery实现仿美橙互联两级导航菜单效果完整实例
2015/09/17 Javascript
JavaScript实现上下浮动的窗口效果代码
2015/10/12 Javascript
Web前端框架Angular4.0.0 正式版发布
2017/03/28 Javascript
vue.js实现用户评论、登录、注册、及修改信息功能
2020/05/30 Javascript
JavaScript实现的可变动态数字键盘控件方式实例代码
2017/07/15 Javascript
Vue.JS项目中5个经典Vuex插件
2017/11/28 Javascript
老生常谈JS中的继承及实现代码
2018/07/06 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
微信小程序如何使用canvas二维码保存至手机相册
2019/07/15 Javascript
用python代码做configure文件
2014/07/20 Python
python里将list中元素依次向前移动一位
2014/09/12 Python
Python删除空文件和空文件夹的方法
2015/07/14 Python
浅谈python中字典append 到list 后值的改变问题
2018/05/04 Python
Form表单及django的form表单的补充
2019/07/25 Python
Python MOCK SERVER moco模拟接口测试过程解析
2020/04/13 Python
python3实现将json对象存入Redis以及数据的导入导出
2020/07/16 Python
详解CSS3中使用gradient实现渐变效果的方法
2015/08/18 HTML / CSS
HTML5的结构和语义(3):语义性的块级元素
2008/10/17 HTML / CSS
中医专业应届生求职信
2013/11/17 职场文书
保洁主管岗位职责
2013/11/20 职场文书
课程设计心得体会
2013/12/28 职场文书
打造完美自荐信
2014/01/24 职场文书
土木工程师职业规划范文
2014/03/07 职场文书
交通事故协议书范文
2014/04/16 职场文书
高一军训决心书
2015/02/05 职场文书
安装harbor作为docker镜像仓库的问题
2022/06/14 Servers