@@ -7,13 +7,19 @@ const localByDefault = require('postcss-modules-local-by-default');
7
7
const extractImports = require ( 'postcss-modules-extract-imports' ) ;
8
8
const modulesScope = require ( 'postcss-modules-scope' ) ;
9
9
const modulesValues = require ( 'postcss-modules-values' ) ;
10
- const loaderUtils = require ( 'loader-utils' ) ;
10
+ const {
11
+ getOptions,
12
+ isUrlRequest,
13
+ urlToRequest,
14
+ getRemainingRequest,
15
+ getCurrentRequest,
16
+ stringifyRequest,
17
+ } = require ( 'loader-utils' ) ;
11
18
12
19
const { importParser, icssParser, urlParser } = require ( './plugins' ) ;
13
20
const {
14
21
getLocalIdent,
15
22
getImportPrefix,
16
- placeholderImportItemReplacer,
17
23
compileExports,
18
24
placholderRegExps,
19
25
} = require ( './utils' ) ;
@@ -22,7 +28,7 @@ const CssSyntaxError = require('./CssSyntaxError');
22
28
23
29
module . exports = function loader ( content , map ) {
24
30
const callback = this . async ( ) ;
25
- const options = loaderUtils . getOptions ( this ) || { } ;
31
+ const options = getOptions ( this ) || { } ;
26
32
const sourceMap = options . sourceMap || false ;
27
33
28
34
/* eslint-disable no-param-reassign */
@@ -43,40 +49,38 @@ module.exports = function loader(content, map) {
43
49
}
44
50
/* eslint-enable no-param-reassign */
45
51
52
+ const parserOptions = { } ;
53
+ const resolveImport = options . import !== false ;
54
+ const resolveUrl = options . url !== false ;
46
55
const loaderContext = this ;
47
- const localIdentName = options . localIdentName || '[hash:base64]' ;
48
- const customGetLocalIdent = options . getLocalIdent || getLocalIdent ;
49
-
50
- const parserOptions = {
51
- url : options . url !== false ,
52
- import : options . import !== false ,
53
- } ;
54
56
55
57
const plugins = [
56
58
modulesValues ,
57
59
localByDefault ( {
58
60
mode : options . modules ? 'local' : 'global' ,
59
61
rewriteUrl ( global , url ) {
60
- if ( parserOptions . url ) {
62
+ if ( resolveUrl ) {
61
63
// eslint-disable-next-line no-param-reassign
62
64
url = url . trim ( ) ;
63
65
64
- if (
65
- ! url . replace ( / \s / g, '' ) . length ||
66
- ! loaderUtils . isUrlRequest ( url )
67
- ) {
66
+ if ( ! url . replace ( / \s / g, '' ) . length || ! isUrlRequest ( url ) ) {
68
67
return url ;
69
68
}
69
+
70
70
if ( global ) {
71
- return loaderUtils . urlToRequest ( url ) ;
71
+ return urlToRequest ( url ) ;
72
72
}
73
73
}
74
+
74
75
return url ;
75
76
} ,
76
77
} ) ,
77
78
extractImports ( ) ,
78
79
modulesScope ( {
79
80
generateScopedName : function generateScopedName ( exportName ) {
81
+ const localIdentName = options . localIdentName || '[hash:base64]' ;
82
+ const customGetLocalIdent = options . getLocalIdent || getLocalIdent ;
83
+
80
84
return customGetLocalIdent ( loaderContext , localIdentName , exportName , {
81
85
regExp : options . localIdentRegExp ,
82
86
hashPrefix : options . hashPrefix || '' ,
@@ -86,11 +90,11 @@ module.exports = function loader(content, map) {
86
90
} ) ,
87
91
] ;
88
92
89
- if ( options . import !== false ) {
93
+ if ( resolveImport ) {
90
94
plugins . push ( importParser ( parserOptions ) ) ;
91
95
}
92
96
93
- if ( options . url !== false ) {
97
+ if ( resolveUrl ) {
94
98
plugins . push ( urlParser ( parserOptions ) ) ;
95
99
}
96
100
@@ -99,12 +103,10 @@ module.exports = function loader(content, map) {
99
103
postcss ( plugins )
100
104
. process ( content , {
101
105
// we need a prefix to avoid path rewriting of PostCSS
102
- from : `/css-loader!${ loaderUtils
103
- . getRemainingRequest ( this )
106
+ from : `/css-loader!${ getRemainingRequest ( this )
104
107
. split ( '!' )
105
108
. pop ( ) } `,
106
- to : loaderUtils
107
- . getCurrentRequest ( this )
109
+ to : getCurrentRequest ( this )
108
110
. split ( '!' )
109
111
. pop ( ) ,
110
112
map : options . sourceMap
@@ -121,78 +123,83 @@ module.exports = function loader(content, map) {
121
123
. warnings ( )
122
124
. forEach ( ( warning ) => this . emitWarning ( new Warning ( warning ) ) ) ;
123
125
124
- // for importing CSS
125
- const importUrlPrefix = getImportPrefix ( this , options ) ;
126
+ const { camelCase, exportOnlyLocals, importLoaders } = options ;
127
+ const { importItems, urlItems, exports } = parserOptions ;
128
+ // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
129
+ const importUrlPrefix = getImportPrefix ( this , importLoaders ) ;
130
+ // Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
131
+ const importItemReplacer = ( item ) => {
132
+ const match = placholderRegExps . importItem . exec ( item ) ;
133
+ const idx = + match [ 1 ] ;
134
+ const importItem = importItems [ idx ] ;
135
+ const importUrl = importUrlPrefix + importItem . url ;
136
+
137
+ if ( exportOnlyLocals ) {
138
+ return `" + require(${ stringifyRequest (
139
+ this ,
140
+ importUrl
141
+ ) } )[${ JSON . stringify ( importItem . export ) } ] + "`;
142
+ }
126
143
127
- let exportJs = compileExports (
128
- parserOptions . exports ,
129
- placeholderImportItemReplacer (
144
+ return `" + require(${ stringifyRequest (
130
145
this ,
131
- parserOptions . importItems ,
132
- importUrlPrefix ,
133
- options . exportOnlyLocals
134
- ) ,
135
- options . camelCase
136
- ) ;
146
+ importUrl
147
+ ) } ).locals[${ JSON . stringify ( importItem . export ) } ] + "`;
148
+ } ;
137
149
138
- if ( options . exportOnlyLocals ) {
139
- if ( exportJs ) {
140
- exportJs = `module.exports = ${ exportJs } ;` ;
141
- }
150
+ let exportCode = compileExports ( exports , camelCase , ( valueAsString ) =>
151
+ valueAsString . replace ( placholderRegExps . importItemG , importItemReplacer )
152
+ ) ;
142
153
143
- return callback ( null , exportJs ) ;
154
+ if ( exportOnlyLocals ) {
155
+ return callback (
156
+ null ,
157
+ exportCode ? `module.exports = ${ exportCode } ;` : exportCode
158
+ ) ;
144
159
}
145
160
146
- let cssAsString = JSON . stringify ( result . css ) ;
147
-
148
161
const alreadyImported = { } ;
149
- const importJs = parserOptions . importItems
162
+ const importCode = importItems
150
163
. filter ( ( imp ) => {
151
164
if ( ! imp . media ) {
152
165
if ( alreadyImported [ imp . url ] ) {
153
166
return false ;
154
167
}
168
+
155
169
alreadyImported [ imp . url ] = true ;
156
170
}
171
+
157
172
return true ;
158
173
} )
159
174
. map ( ( imp ) => {
160
175
const { url } = imp ;
161
176
const media = imp . media || '' ;
162
177
163
- if ( ! loaderUtils . isUrlRequest ( url ) ) {
178
+ if ( ! isUrlRequest ( url ) ) {
164
179
return `exports.push([module.id, ${ JSON . stringify (
165
180
`@import url(${ url } );`
166
181
) } , ${ JSON . stringify ( media ) } ]);`;
167
182
}
168
183
169
184
const importUrl = importUrlPrefix + url ;
170
185
171
- return `exports.i(require(${ loaderUtils . stringifyRequest (
186
+ return `exports.i(require(${ stringifyRequest (
172
187
this ,
173
188
importUrl
174
189
) } ), ${ JSON . stringify ( media ) } );`;
175
190
} , this )
176
191
. join ( '\n' ) ;
177
192
178
- cssAsString = cssAsString . replace (
193
+ let cssAsString = JSON . stringify ( result . css ) . replace (
179
194
placholderRegExps . importItemG ,
180
- placeholderImportItemReplacer (
181
- this ,
182
- parserOptions . importItems ,
183
- importUrlPrefix
184
- )
195
+ importItemReplacer
185
196
) ;
186
197
187
198
// helper for ensuring valid CSS strings from requires
188
- let urlEscapeHelper = '' ;
189
-
190
- if (
191
- options . url !== false &&
192
- parserOptions . urlItems &&
193
- parserOptions . urlItems . length > 0
194
- ) {
195
- urlEscapeHelper = `var escape = require(${ loaderUtils . stringifyRequest (
199
+ let urlEscapeHelperCode = '' ;
200
+
201
+ if ( resolveUrl && urlItems && urlItems . length > 0 ) {
202
+ urlEscapeHelperCode = `var escape = require(${ stringifyRequest (
196
203
this ,
197
204
require . resolve ( './runtime/escape.js' )
198
205
) } );\n`;
@@ -202,7 +209,7 @@ module.exports = function loader(content, map) {
202
209
( item ) => {
203
210
const match = placholderRegExps . urlItem . exec ( item ) ;
204
211
let idx = + match [ 1 ] ;
205
- const urlItem = parserOptions . urlItems [ idx ] ;
212
+ const urlItem = urlItems [ idx ] ;
206
213
const { url } = urlItem ;
207
214
208
215
idx = url . indexOf ( '?#' ) ;
@@ -217,66 +224,66 @@ module.exports = function loader(content, map) {
217
224
// idx === 0 is catched by isUrlRequest
218
225
// in cases like url('webfont.eot?#iefix')
219
226
urlRequest = url . substr ( 0 , idx ) ;
220
- return `" + escape(require(${ loaderUtils . stringifyRequest (
227
+ return `" + escape(require(${ stringifyRequest (
221
228
this ,
222
229
urlRequest
223
230
) } ) + "${ url . substr ( idx ) } ") + "`;
224
231
}
225
232
226
233
urlRequest = url ;
227
234
228
- return `" + escape(require(${ loaderUtils . stringifyRequest (
235
+ return `" + escape(require(${ stringifyRequest (
229
236
this ,
230
237
urlRequest
231
238
) } )) + "`;
232
239
}
233
240
) ;
234
241
}
235
242
236
- if ( exportJs ) {
237
- exportJs = `exports.locals = ${ exportJs } ;` ;
243
+ if ( exportCode ) {
244
+ exportCode = `exports.locals = ${ exportCode } ;` ;
238
245
}
239
246
240
- let moduleJs ;
241
- if ( sourceMap && result . map ) {
242
- /* eslint-disable no-param-reassign */
247
+ let newMap = result . map ;
248
+
249
+ if ( sourceMap && newMap ) {
243
250
// Add a SourceMap
244
- map = result . map . toJSON ( ) ;
251
+ newMap = newMap . toJSON ( ) ;
245
252
246
- if ( map . sources ) {
247
- map . sources = map . sources . map (
253
+ if ( newMap . sources ) {
254
+ newMap . sources = newMap . sources . map (
248
255
( source ) =>
249
256
source
250
257
. split ( '!' )
251
258
. pop ( )
252
259
. replace ( / \\ / g, '/' ) ,
253
260
this
254
261
) ;
255
- map . sourceRoot = '' ;
262
+ newMap . sourceRoot = '' ;
256
263
}
257
264
258
- map . file = map . file
265
+ newMap . file = newMap . file
259
266
. split ( '!' )
260
267
. pop ( )
261
268
. replace ( / \\ / g, '/' ) ;
262
- map = JSON . stringify ( map ) ;
263
- /* eslint-enable no-param-reassign */
264
-
265
- moduleJs = `exports.push([module.id, ${ cssAsString } , "", ${ map } ]);` ;
266
- } else {
267
- moduleJs = `exports.push([module.id, ${ cssAsString } , ""]);` ;
269
+ newMap = JSON . stringify ( newMap ) ;
268
270
}
269
271
272
+ const runtimeCode = `exports = module.exports = require(${ stringifyRequest (
273
+ this ,
274
+ require . resolve ( './runtime/api' )
275
+ ) } )(${ ! ! sourceMap } );`;
276
+ const moduleCode = `exports.push([module.id, ${ cssAsString } , ""${
277
+ newMap ? `,${ newMap } ` : ''
278
+ } ]);`;
279
+
270
280
// Embed runtime
271
281
return callback (
272
282
null ,
273
- `${ urlEscapeHelper } exports = module.exports = require(${ loaderUtils . stringifyRequest (
274
- this ,
275
- require . resolve ( './runtime/api.js' )
276
- ) } )(${ sourceMap } );\n` +
277
- `// imports\n${ importJs } \n\n` +
278
- `// module\n${ moduleJs } \n\n` +
279
- `// exports\n${ exportJs } `
283
+ `${ urlEscapeHelperCode } ${ runtimeCode } \n` +
284
+ `// imports\n${ importCode } \n\n` +
285
+ `// module\n${ moduleCode } \n\n` +
286
+ `// exports\n${ exportCode } `
280
287
) ;
281
288
} )
282
289
. catch ( ( error ) => {
0 commit comments