4

将create-react-app单页面SPA改造成多页面MPA

React推荐的脚手架 create-react-app (以下简称CRA) 默认创建的是单页面(SPA)应用,如果项目需要使用多页面(MPA),则需要对脚手架进行更改

Tips: 以下配置基于 create-react-app@3.4.0 版本

举个栗子,比如我要将原来的index.html扩充出来一个iframe.html页面打包

1、eject 弹出配置

CRA把脚手架相关的配置给隐藏了,需要将配置给弹出

npm run eject

2、更改paths.js

将需要多页面化的html和js入口文件添加到paths中,可参考原有appHtml和appIndexJs即可

module.exports = {
  ...
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),

  // 多页面添加path部分
  iframeHtml: resolveApp('public/iframe.html'),
  appIframeJs: resolveModule(resolveApp, 'src/iframe/index'), // 路径可按需指定
    ...
};

3、更改webpack.config.js

更改entry入口

将原有的单entry入口的数组形式,更改成多chunk入口的对象形式

entry: {
  index: [
    isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
    paths.appIndexJs,
  ].filter(Boolean),
  iframe: [
    isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
    paths.appIframeJs,
  ].filter(Boolean),
}
更改output的filename

在开发模式,将打包的bundle.js加上对应包的chunkName

filename: isEnvProduction ? 'static/js/[name].[contenthash:8].js' : isEnvDevelopment && 'static/js/[name].bundle.js',
更改webpack的插件 ==HtmlWebpackPlugin== 选项
plugins: [
  // Generates an `index.html` file with the <script> injected.
  new HtmlWebpackPlugin(
    Object.assign(
      {},
      {
        inject: true,
        template: paths.appHtml,
        chunks: ['index']
      },
      ...原代码
    )
  ),
  new HtmlWebpackPlugin(
    Object.assign(
      {},
      {
        inject: true,
              template: paths.iframeHtml,
        filename: 'iframe.html',
        chunks: ['iframe']
      },
    )
  ),
  // 如果有多个页面,继续添加即可
]
更改ManifestPlugin中entrypointFiles

在generate函数中,改造entrypointFiles,不然在编译时会出现 Cannot read property 'filter' of undefined 这样的错误

参考 https://github.com/timarney/r... 这个issue,里面有讨论

new ManifestPlugin({
  fileName: 'asset-manifest.json',
  publicPath: paths.publicUrlOrPath,
  generate: (seed, files, entrypoints) => {
    const manifestFiles = files.reduce((manifest, file) => {
      manifest[file.name] = file.path;
      return manifest;
    }, seed);
    // 改造entrypointFiles
    const entrypointFiles = {};
    Object.keys(entrypoints).forEach(entrypoint => {
      entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName => !fileName.endsWith('.map'));
    });

    return {
      files: manifestFiles,
      entrypoints: entrypointFiles,
    };
  }
}),

4、webpackDevServer.config.js中更改historyApiFallback选项

使用rewrites选项

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

5、更改

更改完以上配置后,重启项目即可,访问 localhost:3000/index.html 和 localhost:3000/iframe.html 看效果


Ashin
373 声望12 粉丝

知识珍贵度排名: