React多页应用配置🥷自救指南

1,767 阅读4分钟

前言

目前,大多数时候前端项目是单页应用,只有一个index.html文件。然而,有些时候我们需要使用到多页应用,即多个html文件。

比如,笔者有一个PC端项目,后期迭代时需要支持移动端,由于交互功能一致,但是UI变化大,不合适采用自适应布局的开发方式。因此将移动端组件重写,提取相同的JS公用,将移动端页面打包成h5.html访问,PC端仍是index.html访问。这就涉及到了打包时的多页配置。

多页配置方案

使用CRA脚手架创建的react项目,无法灵活地配置webpack,如果我们想要修改配置,可以采用2种方案。

  1. 使用eject命令将配置文件完全弹射出来,由开发者自由地修改,但是该操作是不可逆的,需谨慎操作。

    弹射出的webpack文件包含scriptsconfig文件夹,其中scripts内包含dev/build/test等脚本命令js,config就是webpack的相关打包js。

    其中,调整多页配置,在config中的paths.jswebpack.config.js中修改。

    // paths.js
    module.exports = {
      // ...
    + appH5Js: resolveModule(resolveApp, 'src/h5/index'),
    }
    
    // webpack.config.js
    // 修改入口文件,出口文件以及html插件
    - entry: paths.appIndexJs,
    + entry: {
    +  main: paths.appIndexJs,
    +  admin: paths.appH5Js,
    + },
    output: {
        // ...,
        filename: isEnvProduction
            ? 'static/js/[name].[contenthash:8].js
    -       : isEnvDevelopment && 'static/js/bundle.js',
    +       : isEnvDevelopment && 'static/js/[name].bundle.js',
    }
    plugins: [
        // ...
        new HtmlWebpackPlugin(
            Object.assign(
            {},
            {
                inject: true,
                template: paths.appHtml,
    +           chunks: ['main'],
             },
             // ...
            )
        ),
    +    // 新增下列配置,可以复制上方的默认HtmlWebpackPlugin插件配置,再相应修改
    +    new HtmlWebpackPlugin(
    +        Object.assign(
    +        {},
    +        {
    +            inject: true,
    +            template: paths.appHtml, // template默认是index.html,如果不需要额外的html文件,可以不填写
    +            filename: 'h5.html',
    +            chunks: ['h5'],
    +         },
    +         // ...
    +        )
    +   )
    ]
    

    修改这2份文件即可完成配置,是不是超级简单吶😬😬

  2. 使用craco等工具,优雅地重写配置。

craco多页配置

笔者也是在实际项目中使用了craco

首先,在项目目录最外层新增craco.config.js文件,采用module.exports导出配置对象,其中有一个属性webpack,里面包含了关于webpack的相关配置,这里就是主战场。

// craco.config.js
module.exports = {
  // ...
  webpack: {
    alias: { /* ... */ },
    plugins: {
      add: [ /* ... */ ],
      remove: [ /* ... */ ],
    },
    configure: { /* ... */},
    configure: (webpackConfig, { env, paths }) => {
      /* ... */
      return webpackConfig;
    },
  },
};

其中,configure是一个函数也可以是对象。当采用对象覆盖无法完成的配置,可以在函数内完成覆盖。经过笔者实操,建议按下方配置一样采用函数写法,避免过多验证浪费表情😖😖。

例如本次需要修改的多页应用配置。

  1. entry下新增入口文件,新增h5/index.js打包入口。

    module.exports = {
        webpack: {
            //...
            configure(webpackConfig, {env, paths}){
                webpackConfig.entry = {
                    main: paths.appIndexJs, // 原来默认的配置
                    h5: path.resolve(__dirname, 'src/h5/index')
                };
    
                return webpackConfig;
            }
        }
    }
    
    
    • env:当前的NODE_ENVdevelopment,production,etc.)
    • paths:包含了所有CRA使用的路径
  2. 修改output配置,以文件名作为打包后js的文件名。

    module.exports = {
        webpack: {
            //...
            configure(webpackConfig, {env, paths}){
                webpackConfig.ouput = {
                    ...webpackConfig.output,
                    filename: 'static/js/[name].bundle.js'
                }
    
                return webpackConfig;
            }
        }
    }
    

    output下还有其它旧配置,解构赋值,新增配置覆盖旧配置。

  3. 新增HTML配置,使用HtmlWebpackPlugin插件将打包生成的js/css文件注入到h5.html

    module.exports = {
    	webpack: {
            //...
            plugins: [
                new HtmlWebpackPlugin(
                    {
                        inject: true,
                        filename: 'h5.html',
                        chunks: ['h5'],
                    }
                ),
            ]
    	}
    }
    

    这里关于HtmlWebpackPlugin的配置还有许多,其中template不写,默认是index.html。如果需要另外的html作为模板,则需要配置对应的绝对路径。

CRA中的new HtmlWebpackPlugin配置中没有chunks项,表明打包产物都会注入到index.html中。如果不想h5相关资源注入到index.html中,可以遍历plugins找到HtmlWebpackPlugin的实例,明确chunks的值,确保index.html中只注入main相关资源。

module.exports = {
    webpack: {
        //...
        configure(webpackConfig, {env, paths}){
            webpackConfig.plugins.map(item => {
                if(item instanceof HtmlWebpackPlugin){
                    if(!item.userOptions.chunks){
                        item.userOptions.chunks = ['main'];
                    }
                };
                return item;
            })
            return webpackConfig;
        }
    }
}

webpackConfig是所有关于webpack的配置,可以通过console.log输出配置的所有内容,了解当前的配置,调整对应配置项。


完整的配置:

// craco.config.js
module.exports = {
    webpack: {
        // ...
        // 添加h5.html文件
        plugins: [
            new HtmlWebpackPlugin(
                {
                    inject: true,
                    template: path.resolve(__dirname, 'public/h5.html'), // html模板的绝对地址
                    filename: 'h5.html',
                    chunks: ['h5'],
                 },
            )
        ],
        configure(webpackConfig, {env, paths}){
            const isEnvProduction = env === 'production';
            const isEnvDevelopment = env === 'development';
            
            // 添加打包入口文件
            webpackConfig.entry = {
                main: paths.appIndexJs,
                h5: path.resolve(__dirname, 'src/h5/index')
            };
            // 修改输出文件名
            webpackConfig.output = {
                ...webpackConfig.output,
                filename: isEnvProduction
                    ? 'static/js/[name].[contenthash:8].js'
                    : isEnvDevelopment && 'static/js/[name].bundle.js'
            };
            // 默认的index.html HtmlWebpackPlugin配置时没有添加chunks,为了只让main注入到index.html,配置chunks
            webpackConfig.plugins.map(item => {
                if(item instanceof HtmlWebpackPlugin){
                    if(!item.userOptions.chunks){
                        item.userOptions.chunks = ['main'];
                    }
                };
                return item;
            });
            // 最后返回更新后的config
            return webpackConfig;
        }
    }
}

注意

  1. entry/output对象是直接覆盖旧配置,因此需要把旧配置解构赋值,新配置放在末尾覆盖旧配置。entry原先是字符串,新增入口文件需调整成对象,还原上main的配置,再新增上h5的配置。(entry支持对象、数字、字符串格式)
  2. 旧配置中有HtmlWebpackPlugin的配置,其中template未配置,默认是以src/index.html为模板文件生成index.html;其中chunks未配置,默认是将所有打包后的js/css都注入到index.html中。为了将对应的js/css注入到对应的html文件中,需添加chunks配置。
  3. configure的第一个参数,是最终使用的配置项,可以console.log查看。

最后

如果一开始对webpack不熟悉,也不知道怎么开始配置,可以新创建一个CRA项目,eject出配置,边看官方文档,边看弹射出的配置文件,直接复制对应配置到实际项目中,修修改改下即可。

如果启动项目仍有报错,可以在craco.config.jsconfigure中打印webpackConfig,看看配置项是否如所愿,一般这里进行修改后,项目可以成功启动。

祝好运,End.