@@ -58,7 +58,7 @@ module.exports = function (content) {
58
58
var bubleOptions = hasBuble && options . buble ? '?' + JSON . stringify ( options . buble ) : ''
59
59
var defaultLoaders = {
60
60
html : templateCompilerPath + '?id=' + moduleId ,
61
- css : styleLoaderPath + '!css-loader' + ( needCssSourceMap ? '?sourceMap' : '' ) ,
61
+ css : ( isServer ? '' : styleLoaderPath + '!' ) + ' css-loader' + ( needCssSourceMap ? '?sourceMap' : '' ) ,
62
62
js : hasBuble ? ( 'buble-loader' + bubleOptions ) : hasBabel ? 'babel-loader' : ''
63
63
}
64
64
@@ -77,7 +77,7 @@ module.exports = function (content) {
77
77
// disable all configuration loaders
78
78
'!!' +
79
79
// get loader string for pre-processors
80
- getLoaderString ( type , part , scoped ) +
80
+ getLoaderString ( type , part , index , scoped ) +
81
81
// select the corresponding part from the vue file
82
82
getSelectorString ( type , index || 0 ) +
83
83
// the url to the actual vuefile
@@ -94,17 +94,42 @@ module.exports = function (content) {
94
94
function getRequireForImportString ( type , impt , scoped ) {
95
95
return loaderUtils . stringifyRequest ( loaderContext ,
96
96
'!!' +
97
- getLoaderString ( type , impt , scoped ) +
97
+ getLoaderString ( type , impt , - 1 , scoped ) +
98
98
impt . src
99
99
)
100
100
}
101
101
102
- function getLoaderString ( type , part , scoped ) {
102
+ function addCssModulesToLoader ( loader , part , index ) {
103
+ if ( ! part . module ) return loader
104
+ var option = options . cssModules || { }
105
+ return loader . replace ( / ( (?: ^ | ! ) c s s (?: - l o a d e r ) ? ) ( \? [ ^ ! ] * ) ? / , function ( m , $1 , $2 ) {
106
+ // $1: !css-loader
107
+ // $2: ?a=b
108
+ var query = loaderUtils . parseQuery ( $2 )
109
+ query . modules = true
110
+ query . importLoaders = true
111
+ query . localIdentName = option . localIdentName || '[hash:base64]'
112
+ if ( index !== - 1 ) {
113
+ // Note:
114
+ // Class name is generated according to its filename.
115
+ // Different <style> tags in the same .vue file may generate same names.
116
+ // Append `_[index]` to class name to avoid this.
117
+ query . localIdentName += '_' + index
118
+ }
119
+ return $1 + '?' + JSON . stringify ( query )
120
+ } )
121
+ }
122
+
123
+ function getLoaderString ( type , part , index , scoped ) {
103
124
var lang = part . lang || defaultLang [ type ]
104
125
var loader = loaders [ lang ]
105
126
var rewriter = type === 'styles' ? styleRewriter + ( scoped ? '&scoped=true!' : '!' ) : ''
106
127
var injectString = ( type === 'script' && query . inject ) ? 'inject!' : ''
107
128
if ( loader !== undefined ) {
129
+ // add css modules
130
+ if ( type === 'styles' ) {
131
+ loader = addCssModulesToLoader ( loader , part , index )
132
+ }
108
133
// inject rewriter before css/html loader for
109
134
// extractTextPlugin use cases
110
135
if ( rewriterInjectRE . test ( loader ) ) {
@@ -121,7 +146,8 @@ module.exports = function (content) {
121
146
case 'template' :
122
147
return defaultLoaders . html + '!' + templateLoaderPath + '?raw&engine=' + lang + '!'
123
148
case 'styles' :
124
- return defaultLoaders . css + '!' + rewriter + lang + '!'
149
+ loader = addCssModulesToLoader ( defaultLoaders . css , part , index )
150
+ return loader + '!' + rewriter + lang + '!'
125
151
case 'script' :
126
152
return injectString + lang + '!'
127
153
}
@@ -146,13 +172,42 @@ module.exports = function (content) {
146
172
var hasScoped = parts . styles . some ( function ( s ) { return s . scoped } )
147
173
var output = 'var __vue_exports__, __vue_options__\n'
148
174
175
+ // css modules
176
+ output += 'var __vue_styles__ = {}\n'
177
+ var cssModules = { }
178
+
149
179
// add requires for styles
150
- if ( ! isServer && parts . styles . length ) {
180
+ if ( parts . styles . length ) {
151
181
output += '\n/* styles */\n'
152
182
parts . styles . forEach ( function ( style , i ) {
153
- output += style . src
183
+ var moduleName = ( style . module === true ) ? '$style' : style . module
184
+
185
+ // require style
186
+ if ( isServer && ! moduleName ) return
187
+ var requireString = style . src
154
188
? getRequireForImport ( 'styles' , style , style . scoped )
155
189
: getRequire ( 'styles' , style , i , style . scoped )
190
+
191
+ // setCssModule
192
+ if ( moduleName ) {
193
+ if ( moduleName in cssModules ) {
194
+ loaderContext . emitError ( 'CSS module name "' + moduleName + '" is not unique!' )
195
+ output += requireString
196
+ } else {
197
+ cssModules [ moduleName ] = true
198
+
199
+ // `style-loader` exposes the name-to-hash map directly
200
+ // `css-loader` exposes it in `.locals`
201
+ // We drop `style-loader` in SSR, and add `.locals` here.
202
+ if ( isServer ) {
203
+ requireString += '.locals'
204
+ }
205
+
206
+ output += '__vue_styles__["' + moduleName + '"] = ' + requireString + '\n'
207
+ }
208
+ } else {
209
+ output += requireString
210
+ }
156
211
} )
157
212
}
158
213
@@ -205,6 +260,16 @@ module.exports = function (content) {
205
260
exports += '__vue_options__._scopeId = "' + moduleId + '"\n'
206
261
}
207
262
263
+ if ( Object . keys ( cssModules ) . length ) {
264
+ // inject style modules as computed properties
265
+ exports +=
266
+ 'if (!__vue_options__.computed) __vue_options__.computed = {}\n' +
267
+ 'Object.keys(__vue_styles__).forEach(function (key) {\n' +
268
+ 'var module = __vue_styles__[key]\n' +
269
+ '__vue_options__.computed[key] = function () { return module }\n' +
270
+ '})\n'
271
+ }
272
+
208
273
if ( ! query . inject ) {
209
274
output += exports
210
275
// hot reload
0 commit comments