script-attr-plugin.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { rspack } from '@rspack/core';
  2. const hasADDPrefetch = []
  3. let runtimeContent = ''
  4. class ScriptAddAttributePlugin {
  5. constructor(options) {
  6. this.options = options;
  7. }
  8. apply(compiler) {
  9. compiler.hooks.compilation.tap('AddAttributePlugin', compilation => {
  10. rspack.HtmlRspackPlugin.getCompilationHooks(
  11. compilation,
  12. ).alterAssetTags.tapPromise('AddAttributePlugin', async pluginArgs => {
  13. pluginArgs.assetTags.scripts = pluginArgs.assetTags.scripts.map(tag => {
  14. if (tag.attributes.src && tag.attributes.src.includes('runtime')) {
  15. runtimeContent = compilation.assets[tag.attributes.src] ? compilation.assets[tag.attributes.src].source() : '';
  16. return tag;
  17. }
  18. if (tag.tagName === 'script') {
  19. tag.attributes.prefetch = true;
  20. }
  21. if (tag.tagName === 'link') {
  22. tag.attributes.prefetch = true;
  23. }
  24. hasADDPrefetch.push(tag.attributes.src)
  25. return tag;
  26. }).filter(tag => !tag.attributes.src.includes('runtime'));
  27. })
  28. });
  29. }
  30. }
  31. class InjectContentPlugin {
  32. constructor(options) {
  33. this.options = options;
  34. }
  35. apply(compiler) {
  36. compiler.hooks.compilation.tap('InjectContentPlugin', compilation => {
  37. rspack.HtmlRspackPlugin.getCompilationHooks(
  38. compilation,
  39. ).afterTemplateExecution.tapPromise(
  40. 'InjectContentPlugin',
  41. async pluginArgs => {
  42. const allAssets = compilation.getAssets();
  43. const jsFiles = allAssets
  44. .filter(asset => asset.name.endsWith('.js'))
  45. .map(asset => asset.name);
  46. const notAddedFiles = jsFiles.filter(file => !hasADDPrefetch.includes(file) && !file.includes('runtime'));
  47. const scriptTags = notAddedFiles.map(file => `<script prefetch src="${file}"></script>`).join('\n');
  48. if (runtimeContent) {
  49. pluginArgs.html = pluginArgs.html.replace('</body>', `<script>${runtimeContent}</script></body>`);
  50. const runtimeFiles = allAssets
  51. .filter(asset => asset.name.includes('runtime'))
  52. .map(asset => asset.name);
  53. runtimeFiles.forEach(filename => {
  54. // 从compilation中删除runtime文件
  55. compilation.deleteAsset(filename);
  56. });
  57. }
  58. pluginArgs.html = pluginArgs.html.replace(
  59. '</body>',
  60. `${scriptTags}\n</body>`
  61. );
  62. },
  63. );
  64. });
  65. }
  66. }
  67. export { ScriptAddAttributePlugin, InjectContentPlugin }