[vue-loader] allow using builtin extractCSS functionality

This option is disabled by default and won't affect exiting users.
However users can easily enable this option using `nuxt.build.extractCSS`

Implementation is according to:
- https://github.com/vuejs/vue-loader/tree/master/docs/en/configurations
- https://ssr.vuejs.org/en/css.html
- https://github.com/vuejs/vue-hackernews-2.0/tree/master/build
This commit is contained in:
Pooya Parsa 2017-04-30 16:28:25 +04:30
parent 379fb753ca
commit 87172100c7
7 changed files with 56 additions and 14 deletions

View File

@ -1,6 +1,7 @@
module.exports = { module.exports = {
build: { build: {
filenames: { filenames: {
css: 'styles.[chunkhash].css', // default: common.[chunkhash].css
manifest: 'manifest.[hash].js', // default: manifest.[hash].js manifest: 'manifest.[hash].js', // default: manifest.[hash].js
vendor: 'vendor.[hash].js', // default: vendor.bundle.[hash].js vendor: 'vendor.[hash].js', // default: vendor.bundle.[hash].js
app: 'app.[chunkhash].js' // default: nuxt.bundle.[chunkhash].js app: 'app.[chunkhash].js' // default: nuxt.bundle.[chunkhash].js

View File

@ -51,6 +51,7 @@ const defaults = {
analyze: false, analyze: false,
publicPath: '/_nuxt/', publicPath: '/_nuxt/',
filenames: { filenames: {
css: 'common.[chunkhash].css',
manifest: 'manifest.[hash].js', manifest: 'manifest.[hash].js',
vendor: 'vendor.bundle.[hash].js', vendor: 'vendor.bundle.[hash].js',
app: 'nuxt.bundle.[chunkhash].js' app: 'nuxt.bundle.[chunkhash].js'

View File

@ -4,6 +4,8 @@ import vueLoaderConfig from './vue-loader.config'
import { defaults } from 'lodash' import { defaults } from 'lodash'
import { join } from 'path' import { join } from 'path'
import { isUrl, urlJoin } from '../utils' import { isUrl, urlJoin } from '../utils'
import { styleLoader, extractStyles } from './helpers'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -71,15 +73,21 @@ export default function ({ isClient, isServer }) {
cacheDirectory: !!this.dev cacheDirectory: !!this.dev
}) })
}, },
{ test: /\.css$/, loader: 'vue-style-loader!css-loader' }, { test: /\.css$/, use: styleLoader.call(this, 'css') },
{ test: /\.less$/, loader: 'vue-style-loader!css-loader!less-loader' }, { test: /\.less$/, use: styleLoader.call(this, 'less', 'less-loader') },
{ test: /\.sass$/, loader: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' }, { test: /\.sass$/, use: styleLoader.call(this, 'sass', 'sass-loader?indentedSyntax') },
{ test: /\.scss$/, loader: 'vue-style-loader!css-loader!sass-loader' }, { test: /\.scss$/, use: styleLoader.call(this, 'sass', 'sass-loader') },
{ test: /\.styl(us)?$/, loader: 'vue-style-loader!css-loader!stylus-loader' } { test: /\.styl(us)?$/, use: styleLoader.call(this, 'stylus', 'stylus-loader') }
] ]
}, },
plugins: this.options.build.plugins plugins: this.options.build.plugins
} }
// CSS extraction
if (extractStyles.call(this)) {
config.plugins.push(
new ExtractTextPlugin({filename: this.options.build.filenames.css})
)
}
// Add nuxt build loaders (can be configured in nuxt.config.js) // Add nuxt build loaders (can be configured in nuxt.config.js)
config.module.rules = config.module.rules.concat(this.options.build.loaders) config.module.rules = config.module.rules.concat(this.options.build.loaders)
// Return config // Return config

View File

@ -3,12 +3,14 @@
import { each, defaults } from 'lodash' import { each, defaults } from 'lodash'
import webpack from 'webpack' import webpack from 'webpack'
import VueSSRClientPlugin from 'vue-server-renderer/client-plugin' import VueSSRClientPlugin from 'vue-server-renderer/client-plugin'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import HTMLPlugin from 'html-webpack-plugin' import HTMLPlugin from 'html-webpack-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin' import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
import ProgressBarPlugin from 'progress-bar-webpack-plugin' import ProgressBarPlugin from 'progress-bar-webpack-plugin'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import OfflinePlugin from 'offline-plugin' import OfflinePlugin from 'offline-plugin'
import base from './base.config.js' import base from './base.config.js'
import { extractStyles } from './helpers'
import { resolve } from 'path' import { resolve } from 'path'
/* /*
@ -55,9 +57,18 @@ export default function () {
// Extract vendor chunks for better caching // Extract vendor chunks for better caching
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', name: 'vendor',
filename: this.options.build.filenames.vendor filename: this.options.build.filenames.vendor,
minChunks (module) {
// A module is extracted into the vendor chunk when...
return (
// If it's inside node_modules
/node_modules/.test(module.context) &&
// Do not externalize if the request is a CSS file
!/\.css$/.test(module.request)
)
}
}), }),
// Extract manifest // Extract webpack runtime & manifest
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
name: 'manifest', name: 'manifest',
minChunks: Infinity, minChunks: Infinity,
@ -68,6 +79,7 @@ export default function () {
template: this.options.appTemplatePath, template: this.options.appTemplatePath,
inject: false // <- Resources will be injected using vue server renderer inject: false // <- Resources will be injected using vue server renderer
}), }),
// Generate client manifest json
new VueSSRClientPlugin({ new VueSSRClientPlugin({
filename: 'client-manifest.json' filename: 'client-manifest.json'
}) })

15
lib/webpack/helpers.js Executable file
View File

@ -0,0 +1,15 @@
import ExtractTextPlugin from 'extract-text-webpack-plugin'
export function extractStyles(ext) {
return !this.dev && !!this.options.build.extractCSS && this.options.build.extractCSS[ext] !== false
}
export function styleLoader(ext, loader = []) {
if (!extractStyles.call(this, ext)) {
return ['vue-style-loader', 'css-loader'].concat(loader)
}
return ExtractTextPlugin.extract({
use: ['css-loader?minimize'].concat(loader),
fallback: 'vue-style-loader'
})
}

View File

@ -1,6 +1,7 @@
'use strict' 'use strict'
import { defaults } from 'lodash' import { defaults } from 'lodash'
import { extractStyles, styleLoader } from './helpers'
export default function ({ isClient }) { export default function ({ isClient }) {
let babelOptions = JSON.stringify(defaults(this.options.build.babel, { let babelOptions = JSON.stringify(defaults(this.options.build.babel, {
@ -8,18 +9,21 @@ export default function ({ isClient }) {
babelrc: false, babelrc: false,
cacheDirectory: !!this.dev cacheDirectory: !!this.dev
})) }))
// https://github.com/vuejs/vue-loader/blob/master/docs/en/configurations
let config = { let config = {
postcss: this.options.build.postcss, postcss: this.options.build.postcss,
loaders: { loaders: {
'js': 'babel-loader?' + babelOptions, 'js': 'babel-loader?' + babelOptions,
'css': 'vue-style-loader!css-loader', 'css': styleLoader.call(this, 'css'),
'less': 'vue-style-loader!css-loader!less-loader', 'less': styleLoader.call(this, 'less', 'less-loader'),
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax', 'sass': styleLoader.call(this, 'sass', 'sass-loader?indentedSyntax'),
'scss': 'vue-style-loader!css-loader!sass-loader', 'scss': styleLoader.call(this, 'sass', 'scss-loader'),
'stylus': 'vue-style-loader!css-loader!stylus-loader', 'stylus': styleLoader.call(this, 'stylus', 'stylus-loader'),
'styl': 'vue-style-loader!css-loader!stylus-loader' 'styl': styleLoader.call(this, 'stylus', 'stylus-loader')
}, },
preserveWhitespace: false preserveWhitespace: false,
extractCSS: extractStyles.call(this, 'vue')
} }
// Return the config // Return the config
return config return config

View File

@ -62,6 +62,7 @@
"compression": "^1.6.2", "compression": "^1.6.2",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"debug": "^2.6.6", "debug": "^2.6.6",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1", "file-loader": "^0.11.1",
"friendly-errors-webpack-plugin": "^1.6.1", "friendly-errors-webpack-plugin": "^1.6.1",
"fs-extra": "^3.0.0", "fs-extra": "^3.0.0",