55
66"use strict" ;
77
8- const { ConcatSource, RawSource, ReplaceSource } = require ( "webpack-sources" ) ;
8+ const {
9+ ConcatSource,
10+ RawSource,
11+ ReplaceSource,
12+ SourceMapSource
13+ } = require ( "webpack-sources" ) ;
914const { UsageState } = require ( "../ExportsInfo" ) ;
1015const Generator = require ( "../Generator" ) ;
1116const InitFragment = require ( "../InitFragment" ) ;
@@ -20,7 +25,7 @@ const RuntimeGlobals = require("../RuntimeGlobals");
2025const Template = require ( "../Template" ) ;
2126const CssImportDependency = require ( "../dependencies/CssImportDependency" ) ;
2227const HarmonyImportSideEffectDependency = require ( "../dependencies/HarmonyImportSideEffectDependency" ) ;
23- const { getUndoPath } = require ( "../util/identifier" ) ;
28+
2429const memoize = require ( "../util/memoize" ) ;
2530
2631/** @typedef {import("webpack-sources").Source } Source */
@@ -127,12 +132,12 @@ class CssGenerator extends Generator {
127132 }
128133
129134 /**
130- * Generate CSS code for the current module
131- * @param {NormalModule } module the module to generate CSS code for
135+ * Generate CSS source for the current module
136+ * @param {NormalModule } module the module to generate CSS source for
132137 * @param {GenerateContext } generateContext the generate context
133- * @returns {string } the CSS code as string
138+ * @returns {Source | null } the CSS source
134139 */
135- _generateContentCode ( module , generateContext ) {
140+ _generateContentSource ( module , generateContext ) {
136141 const moduleSourceContent = /** @type {Source } */ (
137142 this . generate ( module , {
138143 ...generateContext ,
@@ -141,26 +146,19 @@ class CssGenerator extends Generator {
141146 ) ;
142147
143148 if ( ! moduleSourceContent ) {
144- return "" ;
149+ return null ;
145150 }
146151
147152 const compilation = generateContext . runtimeTemplate . compilation ;
148- const { path : filename } = compilation . getPathWithInfo (
149- compilation . outputOptions . cssChunkFilename ,
150- {
151- runtime : generateContext . runtime ,
152- contentHashType : "css"
153- }
154- ) ;
155- const undoPath = getUndoPath (
156- filename ,
157- compilation . outputOptions . path ,
158- false
159- ) ;
153+ // For non-link exportTypes (style, text, css-style-sheet), url() in the CSS
154+ // is resolved relative to the document URL (for <style> tags and CSSStyleSheet),
155+ // not relative to any output file. Use empty undoPath so urls are relative to
156+ // the output root.
157+ const undoPath = "" ;
160158
161159 const CssModulesPlugin = getCssModulesPlugin ( ) ;
162160 const hooks = CssModulesPlugin . getCompilationHooks ( compilation ) ;
163- const renderedSource = CssModulesPlugin . renderModule (
161+ return CssModulesPlugin . renderModule (
164162 /** @type {CssModule } */ ( module ) ,
165163 {
166164 undoPath,
@@ -170,13 +168,23 @@ class CssGenerator extends Generator {
170168 } ,
171169 hooks
172170 ) ;
171+ }
173172
174- if ( ! renderedSource ) {
175- return "" ;
173+ /**
174+ * Convert a CSS Source to a JS string literal Source, preserving source map.
175+ * Wraps the CSS content with JSON.stringify so it can be embedded in JS code.
176+ * @param {Source } cssSource the CSS source
177+ * @param {NormalModule } module the module
178+ * @returns {Source } a Source representing a JS string literal
179+ */
180+ _cssSourceToJsStringLiteral ( cssSource , module ) {
181+ const { source, map } = cssSource . sourceAndMap ( ) ;
182+ const content = /** @type {string } */ ( source ) ;
183+ const escaped = JSON . stringify ( content ) ;
184+ if ( map ) {
185+ return new SourceMapSource ( escaped , module . identifier ( ) , map , content ) ;
176186 }
177-
178- const content = renderedSource . source ( ) ;
179- return typeof content === "string" ? content : content . toString ( "utf8" ) ;
187+ return new RawSource ( escaped ) ;
180188 }
181189
182190 /**
@@ -296,17 +304,22 @@ class CssGenerator extends Generator {
296304 const generateContentCode = ( ) => {
297305 switch ( exportType ) {
298306 case "style" : {
299- const moduleCode = this . _generateContentCode (
307+ const cssSource = this . _generateContentSource (
300308 module ,
301309 generateContext
302310 ) ;
311+ if ( ! cssSource ) return "" ;
303312 const moduleId = generateContext . chunkGraph . getModuleId ( module ) ;
304313
305314 generateContext . runtimeRequirements . add (
306315 RuntimeGlobals . cssInjectStyle
307316 ) ;
308317
309- return `${ RuntimeGlobals . cssInjectStyle } (${ JSON . stringify ( moduleId || "" ) } , ${ JSON . stringify ( moduleCode ) } );` ;
318+ return new ConcatSource (
319+ `${ RuntimeGlobals . cssInjectStyle } (${ JSON . stringify ( moduleId || "" ) } , ` ,
320+ this . _cssSourceToJsStringLiteral ( cssSource , module ) ,
321+ ");"
322+ ) ;
310323 }
311324
312325 default :
@@ -325,15 +338,19 @@ class CssGenerator extends Generator {
325338 }
326339 } ;
327340 const generateExportCode = ( ) => {
341+ /** @returns {Source } generated CSS text as JS expression */
328342 const generateCssText = ( ) => {
329343 const importCode = this . _generateImportCode (
330344 module ,
331345 generateContext
332346 ) ;
333- const moduleCode = this . _generateContentCode (
347+ const cssSource = this . _generateContentSource (
334348 module ,
335349 generateContext
336350 ) ;
351+ const jsLiteral = cssSource
352+ ? this . _cssSourceToJsStringLiteral ( cssSource , module )
353+ : new RawSource ( '""' ) ;
337354
338355 if ( importCode . length > 0 ) {
339356 if (
@@ -344,17 +361,24 @@ class CssGenerator extends Generator {
344361 RuntimeGlobals . cssMergeStyleSheets
345362 ) ;
346363
347- return `${ RuntimeGlobals . cssMergeStyleSheets } ([${ [ ...importCode . map ( ( part ) => part . expr ) , JSON . stringify ( moduleCode ) ] . join ( ", " ) } ])` ;
364+ const args = importCode . map ( ( part ) => part . expr ) ;
365+ return new ConcatSource (
366+ `${ RuntimeGlobals . cssMergeStyleSheets } ([${ args . join ( ", " ) } , ` ,
367+ jsLiteral ,
368+ "])"
369+ ) ;
348370 }
349- return generateContext . runtimeTemplate . concatenation (
350- ...importCode ,
351- moduleCode
371+ return new ConcatSource (
372+ `${ generateContext . runtimeTemplate . concatenation (
373+ ...importCode
374+ ) } + `,
375+ jsLiteral
352376 ) ;
353377 }
354- return JSON . stringify ( moduleCode ) ;
378+ return jsLiteral ;
355379 } ;
356380 /**
357- * @returns {string | null } the default export
381+ * @returns {Source | null } the default export
358382 */
359383 const generateJSDefaultExport = ( ) => {
360384 switch ( exportType ) {
@@ -364,12 +388,20 @@ class CssGenerator extends Generator {
364388 case "css-style-sheet" : {
365389 const constOrVar =
366390 generateContext . runtimeTemplate . renderConst ( ) ;
367- return `(${ generateContext . runtimeTemplate . basicFunction ( "" , [
368- `${ constOrVar } cssText = ${ generateCssText ( ) } ;` ,
369- `${ constOrVar } sheet = new CSSStyleSheet();` ,
370- "sheet.replaceSync(cssText);" ,
371- "return sheet;"
372- ] ) } )()`;
391+ const cssText = generateCssText ( ) ;
392+ const fnPrefix =
393+ generateContext . runtimeTemplate . supportsArrowFunction ( )
394+ ? "() => {\n"
395+ : "function() {\n" ;
396+ const body =
397+ `${ constOrVar } sheet = new CSSStyleSheet();\n` +
398+ "sheet.replaceSync(cssText);\n" +
399+ "return sheet;\n" ;
400+ return new ConcatSource (
401+ `(${ fnPrefix } ${ constOrVar } cssText = ` ,
402+ cssText ,
403+ `;\n${ body } })()`
404+ ) ;
373405 }
374406 default :
375407 return null ;
@@ -378,18 +410,8 @@ class CssGenerator extends Generator {
378410
379411 const isCSSModule = /** @type {BuildMeta } */ ( module . buildMeta )
380412 . isCSSModule ;
413+ /** @type {Source | null } */
381414 const defaultExport = generateJSDefaultExport ( ) ;
382- /**
383- * @param {string } name the export name
384- * @param {string } value the export value
385- * @returns {string } the value to be used in the export
386- */
387- const stringifyExportValue = ( name , value ) => {
388- if ( defaultExport ) {
389- return name === "default" ? value : JSON . stringify ( value ) ;
390- }
391- return JSON . stringify ( value ) ;
392- } ;
393415
394416 /** @type {BuildInfo } */
395417 ( module . buildInfo ) . cssData = cssData ;
@@ -399,14 +421,7 @@ class CssGenerator extends Generator {
399421 generateContext . runtimeRequirements . add ( RuntimeGlobals . module ) ;
400422 }
401423
402- if ( defaultExport ) {
403- cssData . exports . set (
404- "default" ,
405- /** @type {string } */ ( defaultExport )
406- ) ;
407- }
408-
409- if ( cssData . exports . size === 0 && ! isCSSModule ) {
424+ if ( ! defaultExport && cssData . exports . size === 0 && ! isCSSModule ) {
410425 return new RawSource ( "" ) ;
411426 }
412427
@@ -416,6 +431,28 @@ class CssGenerator extends Generator {
416431 const usedIdentifiers = new Set ( ) ;
417432 const { RESERVED_IDENTIFIER } = getPropertyName ( ) ;
418433
434+ if ( defaultExport ) {
435+ const usedName = generateContext . moduleGraph
436+ . getExportInfo ( module , "default" )
437+ . getUsedName ( "default" , generateContext . runtime ) ;
438+ if ( usedName ) {
439+ let identifier = Template . toIdentifier ( usedName ) ;
440+ if ( RESERVED_IDENTIFIER . has ( identifier ) ) {
441+ identifier = `_${ identifier } ` ;
442+ }
443+ usedIdentifiers . add ( identifier ) ;
444+ generateContext . concatenationScope . registerExport (
445+ "default" ,
446+ identifier
447+ ) ;
448+ source . add (
449+ `${ generateContext . runtimeTemplate . renderConst ( ) } ${ identifier } = `
450+ ) ;
451+ source . add ( defaultExport ) ;
452+ source . add ( ";\n" ) ;
453+ }
454+ }
455+
419456 for ( const [ name , v ] of cssData . exports ) {
420457 const usedName = generateContext . moduleGraph
421458 . getExportInfo ( module , name )
@@ -439,7 +476,7 @@ class CssGenerator extends Generator {
439476 identifier
440477 ) ;
441478 source . add (
442- `${ generateContext . runtimeTemplate . renderConst ( ) } ${ identifier } = ${ stringifyExportValue ( name , v ) } ;\n`
479+ `${ generateContext . runtimeTemplate . renderConst ( ) } ${ identifier } = ${ JSON . stringify ( v ) } ;\n`
443480 ) ;
444481 }
445482 return source ;
@@ -462,25 +499,40 @@ class CssGenerator extends Generator {
462499 generateContext . runtimeRequirements . add ( RuntimeGlobals . module ) ;
463500
464501 if ( ! isCSSModule && ! needNsObj ) {
465- return new RawSource (
466- `${ module . moduleArgument } .exports = ${ defaultExport } `
502+ return new ConcatSource (
503+ `${ module . moduleArgument } .exports = ` ,
504+ /** @type {Source } */ ( defaultExport )
467505 ) ;
468506 }
469507
470- /** @type {string[] } */
471- const exports = [ ] ;
508+ const result = new ConcatSource ( ) ;
509+ result . add (
510+ `${ needNsObj ? `${ RuntimeGlobals . makeNamespaceObject } (` : "" } ${
511+ module . moduleArgument
512+ } .exports = {\n`
513+ ) ;
514+
515+ if ( defaultExport ) {
516+ result . add ( '\t"default": ' ) ;
517+ result . add ( defaultExport ) ;
518+ if ( cssData . exports . size > 0 ) {
519+ result . add ( ",\n" ) ;
520+ }
521+ }
472522
523+ /** @type {string[] } */
524+ const exportEntries = [ ] ;
473525 for ( const [ name , v ] of cssData . exports ) {
474- exports . push (
475- `\t${ JSON . stringify ( name ) } : ${ stringifyExportValue ( name , v ) } `
526+ exportEntries . push (
527+ `\t${ JSON . stringify ( name ) } : ${ JSON . stringify ( v ) } `
476528 ) ;
477529 }
530+ if ( exportEntries . length > 0 ) {
531+ result . add ( exportEntries . join ( ",\n" ) ) ;
532+ }
478533
479- return new RawSource (
480- `${ needNsObj ? `${ RuntimeGlobals . makeNamespaceObject } (` : "" } ${
481- module . moduleArgument
482- } .exports = {\n${ exports . join ( ",\n" ) } \n}${ needNsObj ? ")" : "" } ;`
483- ) ;
534+ result . add ( `\n}${ needNsObj ? ")" : "" } ;` ) ;
535+ return result ;
484536 } ;
485537
486538 const codeParts = this . _exportsOnly
0 commit comments