React项目如何为构建自动注入的Script标签添加defer/async属性
CRA项目为自动注入的Script/Link标签添加defer/async属性配置方案
CRA构建时自动注入静态资源标签的逻辑由内置的html-webpack-plugin实现,不需要手动修改构建产物,根据项目是否eject选择对应配置方式即可:
未Eject项目(推荐,保留官方升级能力)
使用配置覆写工具修改内置webpack配置即可,以兼容性更好的@craco/craco为例:
- 安装开发依赖
npm i @craco/craco -D - 修改
package.json中的脚本命令,将原有的react-scripts替换为craco:{ "scripts": { "start": "craco start", "build": "craco build", "test": "craco test" } } - 在项目根目录新建
craco.config.js,写入配置逻辑:module.exports = { webpack: { configure: (webpackConfig) => { // 定位内置的html-webpack-plugin实例 const htmlPlugin = webpackConfig.plugins.find( plugin => plugin.constructor.name === 'HtmlWebpackPlugin' ) if (!htmlPlugin) return webpackConfig // 全局给所有注入的script标签加defer,需要async就改为'async' htmlPlugin.userOptions.scriptLoading = 'defer' // 细粒度控制标签属性,支持扩展Link标签配置 htmlPlugin.userOptions.transformTags = (tags) => { return tags.map(tag => { // 处理Script标签:可按chunk路径、资源类型单独给指定资源加属性 if (tag.tagName === 'script') { // 示例:给异步加载的业务chunk单独加async属性 // if (tag.attributes.src?.includes('async-chunk')) { // delete tag.attributes.defer // tag.attributes.async = true // } } // 扩展处理Link标签:可针对CSS、预加载资源做自定义属性配置 if (tag.tagName === 'link') { // 示例:给非关键CSS做延迟加载 // if (tag.attributes.rel === 'stylesheet' && !tag.attributes.href.includes('critical')) { // tag.attributes.media = 'print' // tag.attributes.onload = "this.media='all'" // } } return tag }) } return webpackConfig } } }
如果习惯用react-app-rewired,配置逻辑完全一致,只需要把上述webpack修改逻辑写到根目录的config-overrides.js中即可。
已Eject项目
Eject后可以直接修改内置webpack配置,打开config/webpack.config.js,搜索HtmlWebpackPlugin找到插件配置块:
- 全局生效:直接在配置项中添加
scriptLoading: 'defer',需要async则传值'async' - 细粒度控制:和未Eject场景一致,在插件配置中添加
transformTags方法,自定义标签转换逻辑即可 - 修改完成后保存,重新执行构建命令生效
注意事项
- 同一个Script标签不要同时添加defer和async属性,两者执行逻辑差异较大:async为资源下载完成后立刻执行,会中断HTML解析;defer为HTML全部解析完成后按脚本引入顺序执行,更适合普通业务JS场景
- 配置完成后执行
npm run build,查看build/index.html产物即可验证标签属性是否注入成功 - 所有Link标签的自定义属性需求,都可以在
transformTags的link判断分支中实现,直接修改tag.attributes对象即可
内容的提问来源于stack exchange,提问作者user11392477
相关产品推荐
相关产品推荐

