@@ -5,7 +5,7 @@ var genId = require('./utils/gen-id')
55var querystring = require ( 'querystring' )
66var loaderUtils = require ( 'loader-utils' )
77var normalize = require ( './utils/normalize' )
8- var hasLoader = require ( './utils/has-loader ' )
8+ var tryRequire = require ( './utils/try-require ' )
99
1010// internal lib loaders
1111var selectorPath = normalize . lib ( 'selector' )
@@ -19,8 +19,8 @@ var styleLoaderPath = normalize.dep('vue-style-loader')
1919var hotReloadAPIPath = normalize . dep ( 'vue-hot-reload-api' )
2020
2121// check whether default js loader exists
22- var hasBabel = hasLoader ( 'babel' )
23- var hasBuble = hasLoader ( 'buble' )
22+ var hasBabel = ! ! tryRequire ( 'babel-loader ' )
23+ var hasBuble = ! ! tryRequire ( 'buble-loader ' )
2424
2525var rewriterInjectRE = / \b ( c s s (?: - l o a d e r ) ? (?: \? [ ^ ! ] + ) ? ) (?: ! | $ ) /
2626
@@ -83,7 +83,9 @@ module.exports = function (content) {
8383
8484 var defaultLoaders = {
8585 html : templateCompilerPath + templateCompilerOptions ,
86- css : styleLoaderPath + '!' + 'css-loader' + cssLoaderOptions ,
86+ css : options . extractCSS
87+ ? getCSSExtractLoader ( )
88+ : styleLoaderPath + '!' + 'css-loader' + cssLoaderOptions ,
8789 js : hasBuble ? ( 'buble-loader' + bubleOptions ) : hasBabel ? 'babel-loader' : ''
8890 }
8991
@@ -190,19 +192,29 @@ module.exports = function (content) {
190192
191193 function getRawLoaderString ( type , part , index , scoped ) {
192194 var lang = part . lang || defaultLang [ type ]
193- var loader = loaders [ lang ]
194195
195196 var styleCompiler = ''
196197 if ( type === 'styles' ) {
198+ // style compiler that needs to be applied for all styles
197199 styleCompiler = styleCompilerPath + '?' + JSON . stringify ( {
198200 // a marker for vue-style-loader to know that this is an import from a vue file
199201 vue : true ,
200202 id : moduleId ,
201203 scoped : ! ! scoped ,
202204 hasInlineConfig : ! ! query . postcss
203205 } ) + '!'
206+ // normalize scss/sass
207+ if ( lang === 'sass' ) {
208+ lang = 'sass?indentedSyntax'
209+ } else if ( lang === 'scss' ) {
210+ lang = 'sass'
211+ }
204212 }
205213
214+ var loader = options . extractCSS
215+ ? loaders [ lang ] || getCSSExtractLoader ( lang )
216+ : loaders [ lang ]
217+
206218 var injectString = ( type === 'script' && query . inject )
207219 ? 'inject-loader!'
208220 : ''
@@ -252,7 +264,7 @@ module.exports = function (content) {
252264
253265 // sass => sass-loader
254266 // sass-loader => sass-loader
255- // sass?indentedsyntax !css => sass-loader?indentedSyntax!css-loader
267+ // sass?indentedSyntax !css => sass-loader?indentedSyntax!css-loader
256268 function ensureLoader ( lang ) {
257269 return lang . split ( '!' ) . map ( function ( loader ) {
258270 return loader . replace ( / ^ ( [ \w - ] + ) ( \? .* ) ? / , function ( _ , name , query ) {
@@ -275,6 +287,32 @@ module.exports = function (content) {
275287 }
276288 }
277289
290+ function getCSSExtractLoader ( lang ) {
291+ var extract
292+ var op = options . extractCSS
293+ // extractCSS option is an instance of ExtractTextPlugin
294+ if ( typeof op . extract === 'function' ) {
295+ extract = op . extract
296+ } else {
297+ var plugin = tryRequire ( 'extract-text-webpack-plugin' )
298+ if ( ! plugin ) {
299+ throw new Error (
300+ '[vue-loader] extractCSS: true requires extract-text-webpack-plugin ' +
301+ 'as a peer dependency.'
302+ )
303+ } else {
304+ extract = plugin . extract
305+ }
306+ }
307+ var langLoader = lang
308+ ? ensureBang ( ensureLoader ( lang ) )
309+ : ''
310+ return extract ( {
311+ use : 'css-loader' + cssLoaderOptions + '!' + langLoader ,
312+ fallback : 'vue-style-loader'
313+ } )
314+ }
315+
278316 var output = ''
279317 var parts = parse ( content , fileName , this . sourceMap )
280318 var hasScoped = parts . styles . some ( function ( s ) { return s . scoped } )
0 commit comments