You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Create React App构建阶段为react-scripts生成的script标签添加async属性

当然可以!针对Create React App(基于react-scripts构建)自动注入的主JS脚本添加async属性,有几种实用的方案,不用直接eject也能搞定,下面给你详细拆解:

方案1:用react-app-rewired自定义Webpack配置(推荐,无需eject)

这个方法不用暴露react-scripts的核心配置,还能保留后续版本更新的能力:

  • 首先安装依赖:
npm install --save-dev react-app-rewired customize-cra
  • 在项目根目录新建config-overrides.js文件,写入以下配置:
const { override } = require('customize-cra');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = override((config) => {
  // 找到webpack配置中的HtmlWebpackPlugin实例
  const htmlPlugin = config.plugins.find(plugin => plugin instanceof HtmlWebpackPlugin);
  
  if (htmlPlugin) {
    // 开启async脚本加载模式,所有注入的脚本都会带上async属性
    htmlPlugin.options.scriptLoading = 'async';
    
    // 如果你只想给主脚本(比如main.xxx.js)加async,可以用更精细化的处理:
    // htmlPlugin.options.scripts = htmlPlugin.options.scripts?.map(script => {
    //   if (script.src?.includes('main.')) {
    //     return { ...script, attributes: { async: true } };
    //   }
    //   return script;
    // });
  }
  
  return config;
});
  • 修改package.json中的scripts命令,替换成react-app-rewired:
"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",
  "eject": "react-scripts eject"
}
  • 执行npm run build后,生成的index.html里的主脚本就会自动带上async属性了。
方案2:已eject项目的修改方式(不推荐)

如果你已经执行过npm run eject暴露了配置,可以直接修改webpack配置:

  • 打开项目根目录下的config/webpack.config.js,找到HtmlWebpackPlugin的配置块,添加scriptLoading: 'async'选项:
new HtmlWebpackPlugin(
  Object.assign(
    {},
    {
      inject: true,
      scriptLoading: 'async', // 新增这一行
      template: paths.appHtml,
    },
    isEnvProduction
      ? {
          minify: {
            // 原有压缩配置...
          },
        }
      : undefined
  )
),
  • 保存后重新构建,脚本就会带上async属性。不过要注意,eject后无法再接收react-scripts的官方更新,所以除非必要,不建议用这个方法。
方案3:Post-build脚本修改生成的HTML

如果你不想碰Webpack配置,可以在构建完成后用脚本批量修改生成的index.html:

  • 先安装处理HTML的工具:
npm install --save-dev cheerio
  • 根目录新建postbuild.js文件:
const fs = require('fs');
const cheerio = require('cheerio');

// 指向build后的index.html路径
const htmlPath = './build/index.html';
const htmlContent = fs.readFileSync(htmlPath, 'utf8');
const $ = cheerio.load(htmlContent);

// 给所有包含"main."的脚本标签添加async属性
$('script[src*="main."]').attr('async', '');

// 把修改后的内容写回文件
fs.writeFileSync(htmlPath, $.html());
  • 修改package.json的build命令,让构建完成后自动执行这个脚本:
"scripts": {
  "build": "react-scripts build && node postbuild.js",
  // 其他脚本...
}

这个方法简单直接,但只对生产构建生效,开发环境的动态注入脚本不会被修改。

注意事项
  • async和defer的区别:如果你的脚本有依赖顺序要求(比如第三方库先加载,React再初始化),可以考虑用defer代替async——defer会在DOM加载完成后按脚本顺序执行,而async是脚本加载完成就立即执行,可能打乱顺序。
  • 测试兼容性:虽然现代浏览器都支持这两个属性,但如果需要兼容旧版浏览器,要提前做好测试。
  • React 18+适配:React 18的createRoot初始化逻辑对异步加载脚本的兼容性很好,但还是要测试一下页面初始化是否正常。

内容的提问来源于stack exchange,提问作者Aviral Bajpai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:15:17