CRA多页应用改造方案

391 阅读3分钟

cra(create-react-app)脚手架默认创建的是单页应用,如果想要改造为多页应用,首先要把wepback配置暴露出来,然后自己维护。以下是配置步骤:

  cra版本:4.0.0

弹出后使用的webpack版本

  "webpack": "4.44.2",
  "webpack-dev-server": "3.11.0",
  "webpack-manifest-plugin": "2.2.0",
  "workbox-webpack-plugin": "5.1.4"

1. eject弹出配置

在项目搭建完毕后,第一步操作就是执行弹出操作,暴露出webpack配置。

npm(yarn) run eject 

我在实际运行中,先把原有目录删除一部分,然后搭建了自己的目录结构,最后执行弹出操作,结果报错。所以这一步一定要首先执行。 弹出后,在项目根目录中会多出 configscripts两个文件夹,我们需要维护的webpack配置就在config文件夹中了。

2. paths.js配置

参考原有的配置选项,配置其他页面:

/* config/paths.js */
//原有的
module.exports = {
 ...
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),

...
}
//更改为
module.exports = {
 ...
  appHtml: resolveApp('public/index.html'),
  appQueryHtml: resolveApp('public/query.html'),
  appTicketHtml: resolveApp('public/ticket.html'),
  appOrderHtml: resolveApp('public/order.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index/index'),
  appQueryJs: resolveModule(resolveApp, 'src/query/index'),
  appTicketJs: resolveModule(resolveApp, 'src/ticket/index'),
  appOrderJs: resolveModule(resolveApp, 'src/order/index'),
 ...
 }

注意:在src和public目录中要增加所需要的页面,页面里的内容就照搬index.html和index.js中的就可以。

3. 更改webpack.config.js中的配置

paths.js中的路径配置完成后,就可以愉(踩)快(坑)的配置webpack了。

3.1 改写entry入口

//原有的
entry: isEnvDevelopment && !shouldUseReactRefresh ?
  [
  ...
   webpackDevClientEntry,
  // Finally, this is your app's code:
  paths.appIndexJs,
  ...
  ]:paths.appIndexJs,
  
  //更改为
  entry: isEnvDevelopment && !shouldUseReactRefresh ?
  {
  index:[webpackDevClientEntry,paths.appIndexJs],
  query:[webpackDevClientEntry,paths.appQueryJs],
  ticket:[webpackDevClientEntry,paths.appTicketJs],
  order:[webpackDevClientEntry,paths.appOrderJs]
  }:
  {index:[paths.appIndexJs],
  query:[paths.appQueryJs],
  ticket:[paths.appTicketJs],
  order:[paths.appOrderJs]
  }

3.2 改写output的filename

//原有的
 filename: isEnvProduction
  ? 'static/js/[name].[contenthash:8].js'
  : isEnvDevelopment && 'static/js/bundle.js',

//更改为
filename: isEnvProduction 
    ? 'static/js/[name].[contenthash:8].js' 
    : isEnvDevelopment && 'static/js/[name].js',

3.3 改写plugin中HtmlWebpackPlugin配置

//原有的
plugins:{
  // Generates an `index.html` file with the <script> injected.
      new HtmlWebpackPlugin(
        Object.assign(
          {},
         ...
        ),
   ...
  }
  
 //在照搬原有的配置,增加query、ticket、order
 ...
  new HtmlWebpackPlugin(
         Object.assign(
         {}, {
          inject: true,
          template: paths.appQueryHtml,
         filename: 'query.html',
         chunks: ['query'],
         }...
        )
     ...

3.4 改写plugin中的ManifestPlugin配置

//原有的
...
 const entrypointFiles = entrypoints.main.filter(
      fileName => !fileName.endsWith('.map')
    );
    ...
    
//更改为
 const entrypointFiles = {};
    Object.keys(entrypoints).forEach(entrypoint => {
      entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName => 
      !fileName.endsWith('.map'));
    });
    ...

由于版本的原因,我在参考其他版本的cra配置的时候没有这一项,导致yarn start运行的时候页面无限加载最后连接失败。所以这一步对于新版本来说很有必要,或者直接删除ManifestPlugin配置项。

以上是简单配置,如果页面比较少手动添加即可。如果页面比较多,就需要写一些函数方法,自动查找帮助我们直接添加entryhtmlPlugin部分。

为何选择多页应用?

单页应用

  1. 在SPA(单页)应用中,使用 webpack 构建完成项目之后,会生成一个 html 文件,若干个 js 文件,以及若干个 css 文件。在 html 文件中,会引用所有的 js 和 css 文件。
  2. 缺点:单页面应用,往往对应着高复杂度,比如多层次路由配置、统一数据处理等;首屏比较慢。
  3. 优点:页面切换快。

多页应用

  1. 多页应用中,使用 webpack 构建完成项目之后,会生成多个 html 文件,多个 js 文件,以及多个 css 文件。在每个 html 文件中,只会引用该页面所对应的 js 和 css 文件。
  2. 缺点:每次页面切换都是一次网页刷新并下载相关资源文件,浪费带宽。
  3. 优点:SEO效果好,首页加载快。

对于单页应用的缺点来说,有很多技术方案可以修正,比如首页SSR(服务端渲染)、置react-router路由等插件可以轻松把多页应用改成单页。

多页应用使用场景:

  1. 老旧项目重构(jquery等应用),复用原有页面
  2. 需要迁移到其他项目或平台中

参考文章

  1. React-CRA 多页面配置(npm run eject)
  2. React如何优雅地写单页面应用?
  3. 单页应用和多页应用的区别