buildPluginCss.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.createBuildCssPlugin = void 0;
  7. const path_1 = __importDefault(require("path"));
  8. const buildPluginAsset_1 = require("./buildPluginAsset");
  9. const cssUtils_1 = require("../utils/cssUtils");
  10. const chalk_1 = __importDefault(require("chalk"));
  11. const pluginutils_1 = require("@rollup/pluginutils");
  12. const slash_1 = __importDefault(require("slash"));
  13. const debug = require('debug')('vite:build:css');
  14. const cssInjectionMarker = `__VITE_CSS__`;
  15. const cssInjectionRE = /__VITE_CSS__\(\)/g;
  16. exports.createBuildCssPlugin = ({ root, publicBase, assetsDir, minify = false, inlineLimit = 0, cssCodeSplit = true, preprocessOptions, modulesOptions = {} }) => {
  17. const styles = new Map();
  18. let staticCss = '';
  19. return {
  20. name: 'vite:css',
  21. async transform(css, id) {
  22. if (cssUtils_1.isCSSRequest(id)) {
  23. // if this is a Vue SFC style request, it's already processed by
  24. // rollup-plugin-vue and we just need to rewrite URLs + collect it
  25. const isVueStyle = /\?vue&type=style/.test(id);
  26. const preprocessLang = (id.match(cssUtils_1.cssPreprocessLangRE) ||
  27. [])[1];
  28. const result = isVueStyle
  29. ? css
  30. : await cssUtils_1.compileCss(root, id, {
  31. id: '',
  32. source: css,
  33. filename: id,
  34. scoped: false,
  35. modules: cssUtils_1.cssModuleRE.test(id),
  36. preprocessLang,
  37. preprocessOptions,
  38. modulesOptions
  39. }, true);
  40. let modules;
  41. if (typeof result === 'string') {
  42. css = result;
  43. }
  44. else {
  45. if (result.errors.length) {
  46. console.error(`[vite] error applying css transforms: `);
  47. result.errors.forEach(console.error);
  48. }
  49. css = result.code;
  50. modules = result.modules;
  51. }
  52. // process url() - register referenced files as assets
  53. // and rewrite the url to the resolved public path
  54. if (cssUtils_1.urlRE.test(css)) {
  55. const fileDir = path_1.default.dirname(id);
  56. css = await cssUtils_1.rewriteCssUrls(css, async (rawUrl) => {
  57. const file = path_1.default.posix.isAbsolute(rawUrl)
  58. ? path_1.default.join(root, rawUrl)
  59. : path_1.default.join(fileDir, rawUrl);
  60. let { fileName, content, url } = await buildPluginAsset_1.resolveAsset(file, root, publicBase, assetsDir, inlineLimit);
  61. if (!url && fileName && content) {
  62. url =
  63. 'import.meta.ROLLUP_FILE_URL_' +
  64. this.emitFile({
  65. name: fileName,
  66. type: 'asset',
  67. source: content
  68. });
  69. }
  70. debug(`url(${rawUrl}) -> ${url.startsWith('data:') ? `base64 inlined` : `${file}`}`);
  71. return url;
  72. });
  73. }
  74. styles.set(id, css);
  75. return {
  76. code: modules
  77. ? pluginutils_1.dataToEsm(modules, { namedExports: true })
  78. : (cssCodeSplit
  79. ? // If code-splitting CSS, inject a fake marker to avoid the module
  80. // from being tree-shaken. This preserves the .css file as a
  81. // module in the chunk's metadata so that we can retrieve them in
  82. // renderChunk.
  83. `${cssInjectionMarker}()\n`
  84. : ``) + `export default ${JSON.stringify(css)}`,
  85. map: null,
  86. // #795 css always has side effect
  87. moduleSideEffects: true
  88. };
  89. }
  90. },
  91. async renderChunk(code, chunk) {
  92. let chunkCSS = '';
  93. for (const id in chunk.modules) {
  94. if (styles.has(id)) {
  95. chunkCSS += styles.get(id);
  96. }
  97. }
  98. let match;
  99. while ((match = buildPluginAsset_1.injectAssetRe.exec(chunkCSS))) {
  100. const outputFilepath = publicBase + slash_1.default(path_1.default.join(assetsDir, this.getFileName(match[1])));
  101. chunkCSS = chunkCSS.replace(match[0], outputFilepath);
  102. }
  103. if (cssCodeSplit) {
  104. code = code.replace(cssInjectionRE, '');
  105. // for each dynamic entry chunk, collect its css and inline it as JS
  106. // strings.
  107. if (chunk.isDynamicEntry && chunkCSS) {
  108. chunkCSS = minifyCSS(chunkCSS);
  109. code =
  110. `let ${cssInjectionMarker} = document.createElement('style');` +
  111. `${cssInjectionMarker}.innerHTML = ${JSON.stringify(chunkCSS)};` +
  112. `document.head.appendChild(${cssInjectionMarker});` +
  113. code;
  114. }
  115. else {
  116. staticCss += chunkCSS;
  117. }
  118. return {
  119. code,
  120. map: null
  121. };
  122. }
  123. else {
  124. staticCss += chunkCSS;
  125. return null;
  126. }
  127. },
  128. async generateBundle(_options, bundle) {
  129. // minify css
  130. if (minify && staticCss) {
  131. staticCss = minifyCSS(staticCss);
  132. }
  133. if (staticCss) {
  134. this.emitFile({
  135. name: 'style.css',
  136. type: 'asset',
  137. source: staticCss
  138. });
  139. }
  140. }
  141. };
  142. };
  143. let CleanCSS;
  144. function minifyCSS(css) {
  145. CleanCSS = CleanCSS || require('clean-css');
  146. const res = new CleanCSS({ level: 2, rebase: false }).minify(css);
  147. if (res.errors && res.errors.length) {
  148. console.error(chalk_1.default.red(`[vite] error when minifying css:`));
  149. console.error(res.errors);
  150. }
  151. if (res.warnings && res.warnings.length) {
  152. console.error(chalk_1.default.yellow(`[vite] warnings when minifying css:`));
  153. console.error(res.warnings);
  154. }
  155. return res.styles;
  156. }
  157. //# sourceMappingURL=buildPluginCss.js.map