使用Facebook官方腳手架create-react-app建立React應用,默認只能生成一個SPA,入口是index.html。雖然,SPA的頁面切換可使用前臺路由框架方便(好比React-Router)實現,這也是SPA的推薦作法;但某些狀況下,仍要將頁面切分爲多個頁面,或者在同一個工程開發多個SPA,好比一個是面向客戶的SPA,一個是後臺管理的SPA。javascript
官方給出的回答是:css
Sorry, but Create React App doesn't support this use case.
You can eject and then configure Webpack to have multiple entry points.html
查閱create-react-app和webpack官方文檔,測試以下方式可行,步驟以下:(假設在默認的index.html外增長一個admin.html)java
要實現自定義配置,就須要先Eject出配置(此步驟對create-react-app工程不可逆):npm run eject
react
運行後,package.js會被更新,工程下會多出config目錄,其中有webpack有兩個配置文件,分別對應開發和生產環境(/config/webpack.config.dev.js和/config/webpack.config.prod.js)。這兩個配置文件都要修改,但略有不一樣,下面以dev爲例說明:webpack
因爲是使用webpack打包,先要讓webpack配置出多入口。/config/webpack.config.dev.js默認配置的入口以下:git
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,可作以下修改:github
要點是:web
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。npm
普通的webpack打包工程,到此便可實現多入口,但create-react-app流程更復雜,需繼續修改。
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模板了。
上述配置作完後,理論就能夠打包出多入口的版本;但使用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環境,比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