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 学习笔记(九)call和apply方法
Jan 11 Javascript
心扬JS分页函数代码
Sep 10 Javascript
js下拉菜单语言选项简单实现
Sep 23 Javascript
jQuery原型属性和原型方法详解
Jul 07 Javascript
微信小程序  modal弹框组件详解
Oct 27 Javascript
字太多用...代替的方法(两种)
Mar 15 Javascript
Vue.js仿Metronic高级表格(二)数据渲染
Apr 19 Javascript
解决vue2.x中数据渲染以及vuex缓存的问题
Jul 13 Javascript
React性能优化系列之减少props改变的实现方法
Jan 17 Javascript
vue实现歌手列表字母排序下拉滚动条侧栏排序实时更新
May 14 Javascript
layui动态渲染生成select的option值方法
Sep 23 Javascript
JS 5种遍历对象的方式
Jun 16 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
回首过去10年中最搞笑的10部动漫,哪一部让你节操尽碎?
2020/03/03 日漫
php 执行系统命令的方法
2009/07/07 PHP
Destoon实现多表查询示例
2014/08/21 PHP
PHP输出两个数字中间有多少个回文数的方法
2015/03/23 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
2016/10/14 PHP
php使用preg_match()函数验证ip地址的方法
2017/01/07 PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
2017/03/13 PHP
PHP实现分布式memcache设置web集群session同步的方法
2018/04/10 PHP
常用的javascript function代码
2008/05/23 Javascript
Javascript 类与静态类的实现(续)
2010/04/02 Javascript
parseInt parseFloat js字符串转换数字
2010/08/01 Javascript
js设置cookie过期及清除浏览器对应名称的cookie
2013/10/24 Javascript
jquery实现input输入框实时输入触发事件代码
2014/01/28 Javascript
json定义及jquery操作json的方法
2016/10/03 Javascript
AngularJS操作键值对象类似java的hashmap(填坑小结)
2016/11/12 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
浅谈对Angular中的生命周期钩子的理解
2017/07/31 Javascript
vue 属性拦截实现双向绑定的实例代码
2018/10/24 Javascript
Puppeteer 爬取动态生成的网页实战
2018/11/14 Javascript
JavaScript实现连连看连线算法
2019/01/05 Javascript
Element中的Cascader(级联列表)动态加载省\市\区数据的方法
2019/03/27 Javascript
简述vue-cli中chainWebpack的使用方法
2019/07/30 Javascript
js实现特别简单的钟表效果
2020/09/14 Javascript
[04:44]DOTA2 2017全国高校联赛视频回顾
2017/08/21 DOTA
压缩包密码破解示例分享(类似典破解)
2014/01/17 Python
python以环状形式组合排列图片并输出的方法
2015/03/17 Python
python 列表,数组,矩阵两两转换tolist()的实例
2018/04/04 Python
英国拖鞋购买网站:Bedroom Athletics
2020/02/28 全球购物
电脑教师的教学自我评价
2013/11/26 职场文书
高中生学习生活的自我评价
2013/11/27 职场文书
校班主任推荐信范文
2013/12/03 职场文书
五水共治一句话承诺
2014/05/30 职场文书
应届生求职自荐信
2014/07/04 职场文书
三严三实对照检查材料
2014/09/22 职场文书
2016年乡镇综治宣传月活动总结
2016/03/16 职场文书