使用Facebook官方脚手架create-react-app创建React应用,默认只能生成一个SPA,入口是index.html。虽然,SPA的页面切换可以使用前台路由框架方便(比如React-Router)实现,这也是SPA的推荐做法;但某些情况下,仍要将页面切分为多个页面,或者在同一个工程开发多个SPA,比如一个是面向客户的SPA,一个是后台管理的SPA。

官方给出的回答是:

Sorry, but Create React App doesn't support this use case.
You can eject and then configure Webpack to have multiple entry points.

查阅create-react-app和webpack官方文档,测试如下方式可行,步骤如下:(假设在默认的index.html外增加一个admin.html)

1. Eject

要实现自定义配置,就需要先Eject出配置(此步骤对create-react-app工程不可逆):npm run eject

运行后,package.js会被更新,工程下会多出config目录,其中有webpack有两个配置文件,分别对应开发和生产环境(/config/webpack.config.dev.js和/config/webpack.config.prod.js)。这两个配置文件都要修改,但略有不同,下面以dev为例说明:

2. 修改webpack配置支持多入口

由于是使用webpack打包,先要让webpack配置出多入口。/config/webpack.config.dev.js默认配置的入口如下:

 entry: [
require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('./polyfills'),
require.resolve('react-error-overlay'),
paths.appIndexJs,
],
output: {
path: paths.appBuild,
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath),
},

根据webpack官方文档MULTIPLE ENTRY POINTS,可做如下修改:

要点是:

  1. entry从原来的数组扩展为对象,每个key代表一个入口。
  2. output中的filename要区分输出名,可增加[name]变量,这样会根据entry分别编译出每个entry的js文件。
  3. 由于path里面没有定义新的entry的路径,图方便可以直接写死为paths.appSrc + "/admin.js"
 entry: {
index: [
require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('./polyfills'),
require.resolve('react-error-overlay'),
paths.appIndexJs,
],
admin:[
require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('./polyfills'),
require.resolve('react-error-overlay'),
paths.appSrc + "/admin.js",
]
},
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),
},

这样在src文件夹下,就可以再增加一个admin.js的入口,单独写新的SPA。

普通的webpack打包工程,到此即可实现多入口,但create-react-app流程更复杂,需继续修改。

3. 修改HtmlWebpackPlugin生成多个HTML

Webpack配置多入口后,只是编译出多个入口的JS,同时入口的HTML文件由HtmlWebpackPlugin生成,也需做配置。

原配置如下:

new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),

修改为:

    new HtmlWebpackPlugin({
inject: true,
chunks: ["index"],
template: paths.appHtml,
}),
new HtmlWebpackPlugin({
inject: true,
chunks: ["admin"],
template: paths.appHtml,
filename: 'admin.html',
}),

每调一次HtmlWebpackPlugin生成一次HTML页面,故为admin.html多增加一个节点。其他要点如下:

  • chunks,指明哪些webpack入口的JS会被注入到这个HTML页面。如果不配置,则将所有entry的JS文件都注入HTML。
  • filename,指明生成的HTML路径,如果不配置就是build/index.html,admin配置了新的filename,避免与第一个入口的index.html相互覆盖。

另外,template属性也可以修改为不同的HTML模板,这里的例子,我么就和index入口共用HTML模板了。

4. 修改webpack Dev Server配置

上述配置做完后,理论就可以打包出多入口的版本;但使用npm start启动后,发现无论输入/index.html还是/admin.html,好像都是和原来/index.html显示一样的内容。甚至输入显然不存在的/xxxx.html,也显示为/index.html的内容。

这种现象,初步判断是HTTP服务器把所有请求重定向到了/index.html。对于单页应用,这种做法是没有问题的(本来就一个页面);但我们新增的/admin.html就可以访问了。

参考官方文档The historyApiFallback option,发现是webpack dev server的问题,还要额外做一些配置,需修改/config/webpackDevServer.config.js。

原配置如下:

 historyApiFallback: {
disableDotRule: true,
},

修改为:

   historyApiFallback: {
disableDotRule: true,
// 指明哪些路径映射到哪个html
rewrites: [
{ from: /^\/admin.html/, to: '/build/admin.html' },
]
}

增加的rewrites节点,特别对/admin.html这个URL重定向为/build/admin.html页面(也就是HtmlWebpackPlugin输出的HTML文件路径),这样/admin.html就可以正常访问了。
至此,dev环境的多入口问题就解决了。

prod环境

prod环境,比dev环境更简单。由于不存在webpack Dev Server,直接在config/webpack.config.prod.js同理做2和3步骤即可。

使用npm run build构建prod版本,观察build目录,入口/admin.html的html、js和css文件俱在:

build
├── admin.html
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── service-worker.js
└── static
├── css
│ ├── admin.d41d8cd9.css
│ ├── admin.d41d8cd9.css.map
│ ├── index.9a0fe4f1.css
│ └── index.9a0fe4f1.css.map
├── js
│ ├── admin.f3dca2cd.js
│ ├── admin.f3dca2cd.js.map
│ ├── index.4b87195c.js
│ └── index.4b87195c.js.map
└── media
└── logo.5d5d9eef.svg

修改create-react-app支持多入口的更多相关文章

  1. 深入 Create React App 核心概念

    本文差点难产而死.因为总结的过程中,多次怀疑本文是对官方文档的直接翻译和简单诺列:同时官方文档很全面,全范围的介绍无疑加深了写作的心智负担.但在最终的梳理中,发现走出了一条与众不同的路,于是坚持分享出 ...

  2. 在 .NET Core 5 中集成 Create React app

    翻译自 Camilo Reyes 2021年2月22日的文章 <Integrate Create React app with .NET Core 5> [1] Camilo Reyes ...

  3. 如何扩展 Create React App 的 Webpack 配置

    如何扩展 Create React App 的 Webpack 配置  原文地址https://zhaozhiming.github.io/blog/2018/01/08/create-react-a ...

  4. tap news:week5 0.0 create react app

    参考https://blog.csdn.net/qtfying/article/details/78665664 先创建文件夹 安装create react app 这个脚手架(facebook官方提 ...

  5. 使用create react app教程

    This project was bootstrapped with Create React App. Below you will find some information on how to ...

  6. Create React App

    Facebook开源了React前端框架(MIT Licence),也同时提供了React脚手架 - create-react-app. create-react-app遵循约定优于配置(Coc)的原 ...

  7. Create React App 安装less 报错

    执行npm run eject 暴露模块 安装 npm i  less less-loader -D 1.打开 react app 的 webpack.config.js const sassRege ...

  8. [React] Use the Fragment Short Syntax in Create React App 2.0

    create-react-app version 2.0 added a lot of new features. One of the new features is upgrading to Ba ...

  9. [React] {svg, css module, sass} support in Create React App 2.0

    create-react-app version 2.0 added a lot of new features. One of the new features is added the svgr  ...

  10. create react app 项目部署在Spring(Tomcat)项目中

    网上看了许多,大多数都是nginx做成静态项目,但是这样局限性太多,与Web项目相比许多服务端想做的验证都很麻烦,于是开始了艰难的探索之路,终于在不经意间试出来了,一把辛酸... 正常的打包就不说了. ...

随机推荐

  1. 清除控制台 console

    清除控制台 console.log(1) // console.clear() // CTRL + K // Ctrl + L // process.stdout.write('\033c'); // ...

  2. 调用list(itertools.combinations(keys,3))出现MemoryError的解决办法

    在python3.6中,如下例子: keys = list(newKeywords.keys()) resultkeys = list(itertools.combinations(keys,3)) ...

  3. vs2013编译obs源码

    obs源码下载 一种是在GitHub上下载最新的代码 git clone --recursive https://github.com/jp9000/obs-studio.git --recursiv ...

  4. 网球pt站 T3nnis 情况说明

    网球收藏爱好者们一定知道这个站,网球界的海德堡. 但想进的人发现没什么办法.满世界的找门路.那我说一下具体的情况吧. ************************************ 更新:现 ...

  5. C#socket编程之实现一个简单的TCP通信

    TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TC ...

  6. Apache Solr入门教程(转)

    1.为什么选择Apache Solr Apache Solr是一个功能强大的搜索服务器,它支持REST风格API.Solr是基于Lucene的,Lucene 支持强大的匹配能力,如短语,通配符,连接, ...

  7. 禁止root登陆sshd/并修改默认端口号

    1,新建一个用户: #useradd xxx 2,为新用户设置密码: #passwd xxx 3,修改sshd配置文件 #vi /etc/ssh/sshd_config 查找“#PermitRootL ...

  8. 算法笔记--Splay && Link-Cut-Tree

    Splay 参考:https://tiger0132.blog.luogu.org/slay-notes 普通模板: ; ], val[N], cnt[N], fa[N], sz[N], lazy[N ...

  9. Vue的父子组件间通信及借助$emit和$on解除父子级通信的耦合度高的问题

    1.父子级间通信,父类找子类非常容易,直接在子组件上加一个ref,父组件直接通过this.$refs操作子组件的数据和方法    父 这边子组件中 就完成了父 => 子组件通信 2. 子 =&g ...

  10. cookie与sessionStorage机制

    sessionStorage.localStorage和cookie的区别 共同点:都是保存在浏览器端.且同源的 区别: 1.cookie数据始终在同源的http请求中携带(即使不需要),即cooki ...