serverPluginCss.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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.codegenCss = exports.cssPlugin = exports.debugCSS = void 0;
  7. const path_1 = require("path");
  8. const hash_sum_1 = __importDefault(require("hash-sum"));
  9. const utils_1 = require("../utils");
  10. const serverPluginVue_1 = require("./serverPluginVue");
  11. const cssUtils_1 = require("../utils/cssUtils");
  12. const querystring_1 = __importDefault(require("querystring"));
  13. const chalk_1 = __importDefault(require("chalk"));
  14. const serverPluginClient_1 = require("./serverPluginClient");
  15. const pluginutils_1 = require("@rollup/pluginutils");
  16. exports.debugCSS = require('debug')('vite:css');
  17. exports.cssPlugin = ({ root, app, watcher, resolver }) => {
  18. app.use(async (ctx, next) => {
  19. await next();
  20. // handle .css imports
  21. if (cssUtils_1.isCSSRequest(ctx.path) &&
  22. // note ctx.body could be null if upstream set status to 304
  23. ctx.body) {
  24. const id = JSON.stringify(hash_sum_1.default(ctx.path));
  25. if (utils_1.isImportRequest(ctx)) {
  26. const { css, modules } = await processCss(root, ctx);
  27. ctx.type = 'js';
  28. // we rewrite css with `?import` to a js module that inserts a style
  29. // tag linking to the actual raw url
  30. ctx.body = codegenCss(id, css, modules);
  31. }
  32. }
  33. });
  34. watcher.on('change', (filePath) => {
  35. if (cssUtils_1.isCSSRequest(filePath)) {
  36. const publicPath = resolver.fileToRequest(filePath);
  37. /** filter unused files */
  38. if (!cssUtils_1.cssImporterMap.has(filePath) &&
  39. !processedCSS.has(publicPath) &&
  40. !serverPluginVue_1.srcImportMap.has(filePath)) {
  41. return exports.debugCSS(`${path_1.basename(publicPath)} has changed, but it is not currently in use`);
  42. }
  43. if (serverPluginVue_1.srcImportMap.has(filePath)) {
  44. // handle HMR for <style src="xxx.css">
  45. // it cannot be handled as simple css import because it may be scoped
  46. const styleImport = serverPluginVue_1.srcImportMap.get(filePath);
  47. serverPluginVue_1.vueCache.del(filePath);
  48. vueStyleUpdate(styleImport);
  49. return;
  50. }
  51. // handle HMR for module css
  52. // it cannot be handled as normal css because the js exports may change
  53. if (filePath.includes('.module')) {
  54. moduleCssUpdate(filePath, resolver);
  55. }
  56. const boundaries = cssUtils_1.getCssImportBoundaries(filePath);
  57. if (boundaries.size) {
  58. boundaryCssUpdate(boundaries);
  59. return;
  60. }
  61. // no boundaries
  62. normalCssUpdate(publicPath);
  63. }
  64. else if (cssUtils_1.cssImporterMap.has(filePath)) {
  65. const boundaries = cssUtils_1.getCssImportBoundaries(filePath);
  66. if (boundaries.size) {
  67. boundaryCssUpdate(boundaries);
  68. }
  69. }
  70. });
  71. function boundaryCssUpdate(boundaries) {
  72. for (let boundary of boundaries) {
  73. if (boundary.includes('.module')) {
  74. moduleCssUpdate(boundary, resolver);
  75. }
  76. else if (boundary.includes('.vue')) {
  77. serverPluginVue_1.vueCache.del(utils_1.cleanUrl(boundary));
  78. vueStyleUpdate(resolver.fileToRequest(boundary));
  79. }
  80. else {
  81. normalCssUpdate(resolver.fileToRequest(boundary));
  82. }
  83. }
  84. }
  85. function vueStyleUpdate(styleImport) {
  86. const publicPath = utils_1.cleanUrl(styleImport);
  87. const index = querystring_1.default.parse(styleImport.split('?', 2)[1]).index;
  88. const path = `${publicPath}?type=style&index=${index}`;
  89. console.log(chalk_1.default.green(`[vite:hmr] `) + `${publicPath} updated. (style)`);
  90. watcher.send({
  91. type: 'style-update',
  92. path,
  93. changeSrcPath: path,
  94. timestamp: Date.now()
  95. });
  96. }
  97. function moduleCssUpdate(filePath, resolver) {
  98. // bust process cache
  99. processedCSS.delete(resolver.fileToRequest(filePath));
  100. watcher.handleJSReload(filePath);
  101. }
  102. function normalCssUpdate(publicPath) {
  103. // bust process cache
  104. processedCSS.delete(publicPath);
  105. watcher.send({
  106. type: 'style-update',
  107. path: publicPath,
  108. changeSrcPath: publicPath,
  109. timestamp: Date.now()
  110. });
  111. }
  112. // processed CSS is cached in case the user ticks "disable cache" during dev
  113. // which can lead to unnecessary processing on page reload
  114. const processedCSS = new Map();
  115. async function processCss(root, ctx) {
  116. // source didn't change (marker added by cachedRead)
  117. // just use previously cached result
  118. if (ctx.__notModified && processedCSS.has(ctx.path)) {
  119. return processedCSS.get(ctx.path);
  120. }
  121. const css = (await utils_1.readBody(ctx.body));
  122. const filePath = resolver.requestToFile(ctx.path);
  123. const preprocessLang = (ctx.path.match(cssUtils_1.cssPreprocessLangRE) || [])[1];
  124. const result = await cssUtils_1.compileCss(root, ctx.path, {
  125. id: '',
  126. source: css,
  127. filename: filePath,
  128. scoped: false,
  129. modules: ctx.path.includes('.module'),
  130. preprocessLang,
  131. preprocessOptions: ctx.config.cssPreprocessOptions,
  132. modulesOptions: ctx.config.cssModuleOptions
  133. });
  134. if (typeof result === 'string') {
  135. const res = { css: await cssUtils_1.rewriteCssUrls(css, ctx.path) };
  136. processedCSS.set(ctx.path, res);
  137. return res;
  138. }
  139. cssUtils_1.recordCssImportChain(result.dependencies, filePath);
  140. if (result.errors.length) {
  141. console.error(`[vite] error applying css transforms: `);
  142. result.errors.forEach(console.error);
  143. }
  144. const res = {
  145. css: await cssUtils_1.rewriteCssUrls(result.code, ctx.path),
  146. modules: result.modules
  147. };
  148. processedCSS.set(ctx.path, res);
  149. return res;
  150. }
  151. };
  152. function codegenCss(id, css, modules) {
  153. let code = `import { updateStyle } from "${serverPluginClient_1.clientPublicPath}"\n` +
  154. `const css = ${JSON.stringify(css)}\n` +
  155. `updateStyle(${JSON.stringify(id)}, css)\n`;
  156. if (modules) {
  157. code += pluginutils_1.dataToEsm(modules, { namedExports: true });
  158. }
  159. else {
  160. code += `export default css`;
  161. }
  162. return code;
  163. }
  164. exports.codegenCss = codegenCss;
  165. //# sourceMappingURL=serverPluginCss.js.map