create-react-app如何開發多頁應用

用構建工具create-react-app初始化的項目默認是單頁應用,即整個項目只有一個入口文件和出口文件。但是在實際工作中,由於業務的需求,需要多頁面應用,這裏記錄一下如何修改create-react-app的默認配置來滿足多頁應用的開發。

1、在項目下執行yarn run eject(npm run eject)

此命令對項目工程是不可逆的,且只能執行一次。運行後,package.js會被更新,工程下會多出config目錄,其中有webpack有兩個配置文件,分別對應開發和生產環境(/config/webpack.config.dev.js和/config/webpack.config.prod.js)。這兩個配置文件都要修改,但略有不同,下面以dev爲例說明:

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

  1. 修改config/paths.js文件
    安裝globby yarn add globby
//遍歷public下目錄下的html文件生成arry
const globby = require('globby');
const htmlArray = globby.sync([path.join(resolveApp('public'), '/*.html')]);  


//module.exports 裏面增加
htmlArray

  1. 修改config/webpack.config.dev.js
    要點:
  • entry從原來的數組擴展爲對象,每個key代表一個入口;
  • output中的filename要區分輸出名,可增加[name]變量,這樣會根據entry分別編譯出每個entry的js文件。
  • Webpack配置多入口後,只是編譯出多個入口的JS,同時入口的HTML文件由HtmlWebpackPlugin生成,也需做配置。chunks,指明哪些webpack入口的JS會被注入到這個HTML頁面。如果不配置,則將所有entry的JS文件都注入HTML。filename,指明生成的HTML路徑,如果不配置就是build/index.html,admin配置了新的filename,避免與第一個入口的index.html相互覆蓋。
// 遍歷html
const entryObj = {};
const htmlPluginsAray = paths.htmlArray.map((v)=> {
 const fileParse = path.parse(v);
  
 entryObj[fileParse.name] = [
  require.resolve('./polyfills'),
  require.resolve('react-dev-utils/webpackHotDevClient'),
  `${paths.appSrc}/${fileParse.name}.js`,,
 ]
 return new HtmlWebpackPlugin({
  inject: true,
  chunks:[fileParse.name],
  template: `${paths.appPublic}/${fileParse.base}`,
  filename: fileParse.base
 })
});

<!--entry 替換爲entryObj-->
entry:entryObj

//出口增加[name]
output: {
    path: paths.appBuild,
    pathinfo: true,
    filename: 'static/js/[name].js',
    chunkFilename: 'static/js/[name].chunk.js',
    publicPath: publicPath,
    devtoolModuleFilenameTemplate: info =>
      path.resolve(info.absoluteResourcePath),
  },

<!--替換htmlplugin內容-->
// new HtmlWebpackPlugin({
//  inject: true,
//  chunks: ["index"],
//  template: paths.appPublic + '/index.html',
// }),
...htmlPluginsAray,
  1. 修改config/webpackDevServer.config.js

上述配置做完後,理論就可以打包出多入口的版本;但使用npm start啓動後,發現無論輸入/index.html還是/admin.html,好像都是和原來/index.html顯示一樣的內容。甚至輸入顯然不存在的/xxxx.html,也顯示爲/index.html的內容。

這種現象,初步判斷是HTTP服務器把所有請求重定向到了/index.html。對於單頁應用,這種做法是沒有問題的(本來就一個頁面);但我們新增的/admin.html就不能訪問了。發現是webpack dev server的問題,還要額外做一些配置,需修改/config/webpackDevServer.config.js。

// 增加
const path = require('path');
 
const htmlPluginsAray = paths.htmlArray.map((v)=> {
 const fileParse = path.parse(v);
 return {
  from: new RegExp(`^\/${fileParse.base}`), to: `/build/${fileParse.base}`
 };
});

<!--historyApiFallback 增加 rewrites-->
rewrites: htmlPluginsAray

3、prod環境

  • 修改config/webpack.config.prod.js,同開發環境。
  • 修改scripts/build.js
    增加複製模塊(yarn add cpy
  //增加
  const cpy = require('cpy');
  
  
  // function copyPublicFolder () 替換
  // 原來的方法是複製public下所有的內容,因爲增加了多html 所以不再直接複製過去(直接複製會覆蓋html)
const copyPublicFolder = async() => {
 await cpy([`${paths.appPublic}/*.*`, `!${paths.appPublic}/*.html`], paths.appBuild);
 console.log('copy success!');
 // fs.copySync(paths.appPublic, paths.appBuild, {
 //  dereference: true,
 //  filter: file => file !== paths.appHtml,
 // });
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章