22 MIT License http://www.opensource.org/licenses/mit-license.php
33 Author Tobias Koppers @sokra
44*/
5+ const postcss = require ( 'postcss' ) ;
6+ const localByDefault = require ( 'postcss-modules-local-by-default' ) ;
7+ const extractImports = require ( 'postcss-modules-extract-imports' ) ;
8+ const modulesScope = require ( 'postcss-modules-scope' ) ;
9+ const modulesValues = require ( 'postcss-modules-values' ) ;
510const loaderUtils = require ( 'loader-utils' ) ;
611
7- const processCss = require ( './processCss ' ) ;
12+ const { importParser , icssParser , urlParser } = require ( './plugins ' ) ;
813const {
14+ getLocalIdent,
915 getImportPrefix,
1016 placeholderImportItemReplacer,
1117 compileExports,
18+ placholderRegExps,
1219} = require ( './utils' ) ;
20+ const Warning = require ( './Warning' ) ;
21+ const CssSyntaxError = require ( './CssSyntaxError' ) ;
1322
1423module . exports = function loader ( content , map ) {
1524 const callback = this . async ( ) ;
@@ -34,27 +43,92 @@ module.exports = function loader(content, map) {
3443 }
3544 /* eslint-enable no-param-reassign */
3645
37- processCss (
38- content ,
39- map ,
40- {
41- loaderContext : this ,
42- loaderOptions : options ,
43- sourceMap,
44- } ,
45- ( err , result ) => {
46- if ( err ) {
47- return callback ( err ) ;
48- }
46+ 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+
55+ const plugins = [
56+ modulesValues ,
57+ localByDefault ( {
58+ mode : options . modules ? 'local' : 'global' ,
59+ rewriteUrl ( global , url ) {
60+ if ( parserOptions . url ) {
61+ // eslint-disable-next-line no-param-reassign
62+ url = url . trim ( ) ;
63+
64+ if (
65+ ! url . replace ( / \s / g, '' ) . length ||
66+ ! loaderUtils . isUrlRequest ( url )
67+ ) {
68+ return url ;
69+ }
70+ if ( global ) {
71+ return loaderUtils . urlToRequest ( url ) ;
72+ }
73+ }
74+ return url ;
75+ } ,
76+ } ) ,
77+ extractImports ( ) ,
78+ modulesScope ( {
79+ generateScopedName : function generateScopedName ( exportName ) {
80+ return customGetLocalIdent ( loaderContext , localIdentName , exportName , {
81+ regExp : options . localIdentRegExp ,
82+ hashPrefix : options . hashPrefix || '' ,
83+ context : options . context ,
84+ } ) ;
85+ } ,
86+ } ) ,
87+ ] ;
88+
89+ if ( options . import !== false ) {
90+ plugins . push ( importParser ( parserOptions ) ) ;
91+ }
92+
93+ if ( options . url !== false ) {
94+ plugins . push ( urlParser ( parserOptions ) ) ;
95+ }
96+
97+ plugins . push ( icssParser ( parserOptions ) ) ;
98+
99+ postcss ( plugins )
100+ . process ( content , {
101+ // we need a prefix to avoid path rewriting of PostCSS
102+ from : `/css-loader!${ loaderUtils
103+ . getRemainingRequest ( this )
104+ . split ( '!' )
105+ . pop ( ) } `,
106+ to : loaderUtils
107+ . getCurrentRequest ( this )
108+ . split ( '!' )
109+ . pop ( ) ,
110+ map : options . sourceMap
111+ ? {
112+ prev : map ,
113+ sourcesContent : true ,
114+ inline : false ,
115+ annotation : false ,
116+ }
117+ : null ,
118+ } )
119+ . then ( ( result ) => {
120+ result
121+ . warnings ( )
122+ . forEach ( ( warning ) => this . emitWarning ( new Warning ( warning ) ) ) ;
49123
50124 // for importing CSS
51125 const importUrlPrefix = getImportPrefix ( this , options ) ;
52126
53127 let exportJs = compileExports (
54- result ,
128+ parserOptions . exports ,
55129 placeholderImportItemReplacer (
56130 this ,
57- result ,
131+ parserOptions . importItems ,
58132 importUrlPrefix ,
59133 options . exportOnlyLocals
60134 ) ,
@@ -69,10 +143,10 @@ module.exports = function loader(content, map) {
69143 return callback ( null , exportJs ) ;
70144 }
71145
72- let cssAsString = JSON . stringify ( result . source ) ;
146+ let cssAsString = JSON . stringify ( result . css ) ;
73147
74148 const alreadyImported = { } ;
75- const importJs = result . importItems
149+ const importJs = parserOptions . importItems
76150 . filter ( ( imp ) => {
77151 if ( ! imp . media ) {
78152 if ( alreadyImported [ imp . url ] ) {
@@ -102,48 +176,61 @@ module.exports = function loader(content, map) {
102176 . join ( '\n' ) ;
103177
104178 cssAsString = cssAsString . replace (
105- result . importItemRegExpG ,
106- placeholderImportItemReplacer ( this , result , importUrlPrefix )
179+ placholderRegExps . importItemG ,
180+ placeholderImportItemReplacer (
181+ this ,
182+ parserOptions . importItems ,
183+ importUrlPrefix
184+ )
107185 ) ;
108186
109187 // helper for ensuring valid CSS strings from requires
110188 let urlEscapeHelper = '' ;
111189
112190 if (
113191 options . url !== false &&
114- result . urlItems &&
115- result . urlItems . length > 0
192+ parserOptions . urlItems &&
193+ parserOptions . urlItems . length > 0
116194 ) {
117195 urlEscapeHelper = `var escape = require(${ loaderUtils . stringifyRequest (
118196 this ,
119197 require . resolve ( './runtime/escape.js' )
120198 ) } );\n`;
121199
122- cssAsString = cssAsString . replace ( result . urlItemRegExpG , ( item ) => {
123- const match = result . urlItemRegExp . exec ( item ) ;
124- let idx = + match [ 1 ] ;
125- const urlItem = result . urlItems [ idx ] ;
126- const { url } = urlItem ;
127- idx = url . indexOf ( '?#' ) ;
128- if ( idx < 0 ) {
129- idx = url . indexOf ( '#' ) ;
130- }
131- let urlRequest ;
132- if ( idx > 0 ) {
133- // idx === 0 is catched by isUrlRequest
134- // in cases like url('webfont.eot?#iefix')
135- urlRequest = url . substr ( 0 , idx ) ;
200+ cssAsString = cssAsString . replace (
201+ placholderRegExps . urlItemG ,
202+ ( item ) => {
203+ const match = placholderRegExps . urlItem . exec ( item ) ;
204+ let idx = + match [ 1 ] ;
205+ const urlItem = parserOptions . urlItems [ idx ] ;
206+ const { url } = urlItem ;
207+
208+ idx = url . indexOf ( '?#' ) ;
209+
210+ if ( idx < 0 ) {
211+ idx = url . indexOf ( '#' ) ;
212+ }
213+
214+ let urlRequest ;
215+
216+ if ( idx > 0 ) {
217+ // idx === 0 is catched by isUrlRequest
218+ // in cases like url('webfont.eot?#iefix')
219+ urlRequest = url . substr ( 0 , idx ) ;
220+ return `" + escape(require(${ loaderUtils . stringifyRequest (
221+ this ,
222+ urlRequest
223+ ) } ) + "${ url . substr ( idx ) } ") + "`;
224+ }
225+
226+ urlRequest = url ;
227+
136228 return `" + escape(require(${ loaderUtils . stringifyRequest (
137229 this ,
138230 urlRequest
139- ) } ) + " ${ url . substr ( idx ) } " ) + "`;
231+ ) } )) + "`;
140232 }
141- urlRequest = url ;
142- return `" + escape(require(${ loaderUtils . stringifyRequest (
143- this ,
144- urlRequest
145- ) } )) + "`;
146- } ) ;
233+ ) ;
147234 }
148235
149236 if ( exportJs ) {
@@ -154,7 +241,8 @@ module.exports = function loader(content, map) {
154241 if ( sourceMap && result . map ) {
155242 /* eslint-disable no-param-reassign */
156243 // Add a SourceMap
157- ( { map } = result ) ;
244+ map = result . map . toJSON ( ) ;
245+
158246 if ( map . sources ) {
159247 map . sources = map . sources . map (
160248 ( source ) =>
@@ -166,12 +254,14 @@ module.exports = function loader(content, map) {
166254 ) ;
167255 map . sourceRoot = '' ;
168256 }
257+
169258 map . file = map . file
170259 . split ( '!' )
171260 . pop ( )
172261 . replace ( / \\ / g, '/' ) ;
173262 map = JSON . stringify ( map ) ;
174263 /* eslint-enable no-param-reassign */
264+
175265 moduleJs = `exports.push([module.id, ${ cssAsString } , "", ${ map } ]);` ;
176266 } else {
177267 moduleJs = `exports.push([module.id, ${ cssAsString } , ""]);` ;
@@ -188,6 +278,10 @@ module.exports = function loader(content, map) {
188278 `// module\n${ moduleJs } \n\n` +
189279 `// exports\n${ exportJs } `
190280 ) ;
191- }
192- ) ;
281+ } )
282+ . catch ( ( error ) => {
283+ callback (
284+ error . name === 'CssSyntaxError' ? new CssSyntaxError ( error ) : error
285+ ) ;
286+ } ) ;
193287} ;
0 commit comments