@@ -17,14 +17,15 @@ import {
17
17
getCurrentRequest ,
18
18
stringifyRequest ,
19
19
} from 'loader-utils' ;
20
+ import camelCase from 'lodash/camelCase' ;
20
21
21
22
import schema from './options.json' ;
22
23
import { importParser , icssParser , urlParser } from './plugins' ;
23
24
import {
24
25
getLocalIdent ,
25
26
getImportPrefix ,
26
- compileExports ,
27
27
placholderRegExps ,
28
+ dashesCamelCase ,
28
29
} from './utils' ;
29
30
import Warning from './Warning' ;
30
31
import CssSyntaxError from './CssSyntaxError' ;
@@ -137,10 +138,9 @@ export default function loader(content, map, meta) {
137
138
. forEach ( ( warning ) => this . emitWarning ( new Warning ( warning ) ) ) ;
138
139
139
140
const messages = result . messages || [ ] ;
140
- const { camelCase, exportOnlyLocals, importLoaders } = options ;
141
141
142
142
// Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
143
- const importUrlPrefix = getImportPrefix ( this , importLoaders ) ;
143
+ const importUrlPrefix = getImportPrefix ( this , options . importLoaders ) ;
144
144
145
145
// Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
146
146
const importItemReplacer = ( placeholder ) => {
@@ -162,7 +162,7 @@ export default function loader(content, map, meta) {
162
162
const { item } = message ;
163
163
const importUrl = importUrlPrefix + urlToRequest ( item . url ) ;
164
164
165
- if ( exportOnlyLocals ) {
165
+ if ( options . exportOnlyLocals ) {
166
166
return `" + require(${ stringifyRequest (
167
167
this ,
168
168
importUrl
@@ -175,18 +175,65 @@ export default function loader(content, map, meta) {
175
175
) } ).locals[${ JSON . stringify ( item . export ) } ] + "`;
176
176
} ;
177
177
178
- let exportCode = compileExports ( messages , camelCase , ( valueAsString ) =>
179
- valueAsString . replace ( placholderRegExps . importItemG , importItemReplacer )
180
- ) ;
178
+ const exports = messages
179
+ . filter ( ( message ) => message . type === 'export' )
180
+ . reduce ( ( accumulator , message ) => {
181
+ const { key, value } = message . item ;
182
+
183
+ let valueAsString = JSON . stringify ( value ) ;
184
+
185
+ valueAsString = valueAsString . replace (
186
+ placholderRegExps . importItemG ,
187
+ importItemReplacer
188
+ ) ;
189
+
190
+ function addEntry ( k ) {
191
+ accumulator . push ( `\t${ JSON . stringify ( k ) } : ${ valueAsString } ` ) ;
192
+ }
193
+
194
+ let targetKey ;
195
+
196
+ switch ( options . camelCase ) {
197
+ case true :
198
+ addEntry ( key ) ;
199
+ targetKey = camelCase ( key ) ;
200
+
201
+ if ( targetKey !== key ) {
202
+ addEntry ( targetKey ) ;
203
+ }
204
+ break ;
205
+ case 'dashes' :
206
+ addEntry ( key ) ;
207
+ targetKey = dashesCamelCase ( key ) ;
208
+
209
+ if ( targetKey !== key ) {
210
+ addEntry ( targetKey ) ;
211
+ }
212
+ break ;
213
+ case 'only' :
214
+ addEntry ( camelCase ( key ) ) ;
215
+ break ;
216
+ case 'dashesOnly' :
217
+ addEntry ( dashesCamelCase ( key ) ) ;
218
+ break ;
219
+ default :
220
+ addEntry ( key ) ;
221
+ break ;
222
+ }
223
+
224
+ return accumulator ;
225
+ } , [ ] ) ;
181
226
182
- if ( exportOnlyLocals ) {
227
+ if ( options . exportOnlyLocals ) {
183
228
return callback (
184
229
null ,
185
- exportCode ? `module.exports = ${ exportCode } ;` : exportCode
230
+ exports . length > 0
231
+ ? `module.exports = {\n${ exports . join ( ',\n' ) } \n};`
232
+ : ''
186
233
) ;
187
234
}
188
235
189
- const importCode = messages
236
+ const imports = messages
190
237
. filter ( ( message ) => message . type === 'import' )
191
238
. map ( ( message ) => {
192
239
const { url } = message . item ;
@@ -204,56 +251,52 @@ export default function loader(content, map, meta) {
204
251
this ,
205
252
importUrl
206
253
) } ), ${ JSON . stringify ( media ) } );`;
207
- } , this )
208
- . join ( '\n' ) ;
254
+ } , this ) ;
209
255
210
256
let cssAsString = JSON . stringify ( result . css ) . replace (
211
257
placholderRegExps . importItemG ,
212
258
importItemReplacer
213
259
) ;
214
260
215
- // helper for ensuring valid CSS strings from requires
216
- let urlEscapeHelperCode = '' ;
261
+ // Helper for ensuring valid CSS strings from requires
262
+ let hasUrlEscapeHelper = false ;
217
263
218
264
messages
219
265
. filter ( ( message ) => message . type === 'url' )
220
266
. forEach ( ( message ) => {
221
- if ( ! urlEscapeHelperCode ) {
222
- urlEscapeHelperCode = `var escape = require(${ stringifyRequest (
223
- this ,
224
- require . resolve ( './runtime/escape.js' )
225
- ) } );\n`;
267
+ if ( ! hasUrlEscapeHelper ) {
268
+ imports . push (
269
+ `var urlEscape = require(${ stringifyRequest (
270
+ this ,
271
+ require . resolve ( './runtime/url-escape.js' )
272
+ ) } );`
273
+ ) ;
274
+
275
+ hasUrlEscapeHelper = true ;
226
276
}
227
277
228
278
const { item } = message ;
229
279
const { url, placeholder } = item ;
280
+ // Remove `#hash` and `?#hash` from `require`
281
+ const [ normalizedUrl , singleQuery , hashValue ] = url . split ( / ( \? ) ? # / ) ;
282
+ const hash =
283
+ singleQuery || hashValue
284
+ ? `"${ singleQuery ? '?' : '' } ${ hashValue ? `#${ hashValue } ` : '' } "`
285
+ : '' ;
286
+
287
+ imports . push (
288
+ `var ${ placeholder } = urlEscape(require(${ stringifyRequest (
289
+ this ,
290
+ urlToRequest ( normalizedUrl )
291
+ ) } )${ hash ? ` + ${ hash } ` : '' } );`
292
+ ) ;
230
293
231
294
cssAsString = cssAsString . replace (
232
295
new RegExp ( placeholder , 'g' ) ,
233
- ( ) => {
234
- // Remove `#hash` and `?#hash` from `require`
235
- const [ normalizedUrl , singleQuery , hashValue ] = url . split (
236
- / ( \? ) ? # /
237
- ) ;
238
- const hash =
239
- singleQuery || hashValue
240
- ? `"${ singleQuery ? '?' : '' } ${
241
- hashValue ? `#${ hashValue } ` : ''
242
- } "`
243
- : '' ;
244
-
245
- return `" + escape(require(${ stringifyRequest (
246
- this ,
247
- urlToRequest ( normalizedUrl )
248
- ) } )${ hash ? ` + ${ hash } ` : '' } ) + "`;
249
- }
296
+ ( ) => `" + ${ placeholder } + "`
250
297
) ;
251
298
} ) ;
252
299
253
- if ( exportCode ) {
254
- exportCode = `exports.locals = ${ exportCode } ;` ;
255
- }
256
-
257
300
let newMap = result . map ;
258
301
259
302
if ( sourceMap && newMap ) {
@@ -282,18 +325,21 @@ export default function loader(content, map, meta) {
282
325
const runtimeCode = `exports = module.exports = require(${ stringifyRequest (
283
326
this ,
284
327
require . resolve ( './runtime/api' )
285
- ) } )(${ ! ! sourceMap } );`;
286
- const moduleCode = `exports.push([module.id, ${ cssAsString } , ""${
328
+ ) } )(${ ! ! sourceMap } );\n`;
329
+ const importCode =
330
+ imports . length > 0 ? `// Imports\n${ imports . join ( '\n' ) } \n\n` : '' ;
331
+ const moduleCode = `// Module\nexports.push([module.id, ${ cssAsString } , ""${
287
332
newMap ? `,${ newMap } ` : ''
288
- } ]);`;
333
+ } ]);\n\n`;
334
+ const exportsCode =
335
+ exports . length > 0
336
+ ? `// Exports\nexports.locals = {\n${ exports . join ( ',\n' ) } \n};`
337
+ : '' ;
289
338
290
339
// Embed runtime
291
340
return callback (
292
341
null ,
293
- `${ urlEscapeHelperCode } ${ runtimeCode } \n` +
294
- `// imports\n${ importCode } \n\n` +
295
- `// module\n${ moduleCode } \n\n` +
296
- `// exports\n${ exportCode } `
342
+ runtimeCode + importCode + moduleCode + exportsCode
297
343
) ;
298
344
} )
299
345
. catch ( ( error ) => {
0 commit comments