mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
refactor: style loader and postcss config
This commit is contained in:
parent
3aa8ef6ee2
commit
67d4d5378b
@ -9,7 +9,7 @@ import VueLoader from 'vue-loader'
|
||||
import { isUrl, urlJoin } from '../../common/utils'
|
||||
|
||||
import customLoaders from './loaders'
|
||||
import createStyleLoader from './utils/style-loader'
|
||||
import StyleLoader from './utils/style-loader'
|
||||
import WarnFixPlugin from './plugins/warnfix'
|
||||
import ProgressPlugin from './plugins/progress'
|
||||
import StatsPlugin from './plugins/stats'
|
||||
@ -128,7 +128,11 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
rules() {
|
||||
const styleLoader = createStyleLoader({ isServer: this.isServer })
|
||||
const styleLoader = new StyleLoader(
|
||||
this.options,
|
||||
this.builder.nuxt,
|
||||
{ isServer: this.isServer }
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
@ -146,26 +150,26 @@ export default class WebpackBaseConfig {
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: styleLoader.call(this.builder, 'css')
|
||||
use: styleLoader.apply('css')
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: styleLoader.call(this.builder, 'less', 'less-loader')
|
||||
use: styleLoader.apply('less', 'less-loader')
|
||||
},
|
||||
{
|
||||
test: /\.sass$/,
|
||||
use: styleLoader.call(this.builder, 'sass', {
|
||||
use: styleLoader.apply('sass', {
|
||||
loader: 'sass-loader',
|
||||
options: { indentedSyntax: true }
|
||||
})
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: styleLoader.call(this.builder, 'scss', 'sass-loader')
|
||||
use: styleLoader.apply('scss', 'sass-loader')
|
||||
},
|
||||
{
|
||||
test: /\.styl(us)?$/,
|
||||
use: styleLoader.call(this.builder, 'stylus', 'stylus-loader')
|
||||
use: styleLoader.apply('stylus', 'stylus-loader')
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)$/,
|
||||
|
@ -6,88 +6,114 @@ import createResolver from 'postcss-import-resolver'
|
||||
|
||||
import { isPureObject } from '../../../common/utils'
|
||||
|
||||
export default function postcssConfig() {
|
||||
let config = ـ.cloneDeep(this.options.build.postcss)
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (!config) {
|
||||
return false
|
||||
export default class PostcssConfig {
|
||||
constructor(options, nuxt) {
|
||||
this.nuxt = nuxt
|
||||
this.postcss = options.build.postcss
|
||||
this.srcDir = options.srcDir
|
||||
this.rootDir = options.rootDir
|
||||
this.cssSourceMap = options.build.cssSourceMap
|
||||
this.modulesDir = options.modulesDir
|
||||
}
|
||||
|
||||
// Search for postCSS config file and use it if exists
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
for (let dir of [this.options.srcDir, this.options.rootDir]) {
|
||||
for (let file of [
|
||||
'postcss.config.js',
|
||||
'.postcssrc.js',
|
||||
'.postcssrc',
|
||||
'.postcssrc.json',
|
||||
'.postcssrc.yaml'
|
||||
]) {
|
||||
if (fs.existsSync(path.resolve(dir, file))) {
|
||||
const postcssConfigPath = path.resolve(dir, file)
|
||||
return {
|
||||
sourceMap: this.options.build.cssSourceMap,
|
||||
config: {
|
||||
path: postcssConfigPath
|
||||
get defaultConfig() {
|
||||
return {
|
||||
useConfigFile: false,
|
||||
sourceMap: this.cssSourceMap,
|
||||
plugins: {
|
||||
// https://github.com/postcss/postcss-import
|
||||
'postcss-import': {
|
||||
resolve: createResolver({
|
||||
alias: {
|
||||
'~': path.join(this.srcDir),
|
||||
'~~': path.join(this.rootDir),
|
||||
'@': path.join(this.srcDir),
|
||||
'@@': path.join(this.rootDir)
|
||||
},
|
||||
modules: [
|
||||
this.srcDir,
|
||||
this.rootDir,
|
||||
...this.modulesDir
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
// https://github.com/postcss/postcss-url
|
||||
'postcss-url': {},
|
||||
|
||||
// http://cssnext.io/postcss
|
||||
'postcss-cssnext': {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFromFile() {
|
||||
// Search for postCSS config file and use it if exists
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
for (let dir of [this.srcDir, this.rootDir]) {
|
||||
for (let file of [
|
||||
'postcss.config.js',
|
||||
'.postcssrc.js',
|
||||
'.postcssrc',
|
||||
'.postcssrc.json',
|
||||
'.postcssrc.yaml'
|
||||
]) {
|
||||
if (fs.existsSync(path.resolve(dir, file))) {
|
||||
const postcssConfigPath = path.resolve(dir, file)
|
||||
return {
|
||||
sourceMap: this.cssSourceMap,
|
||||
config: {
|
||||
path: postcssConfigPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize
|
||||
if (Array.isArray(config)) {
|
||||
config = { plugins: config }
|
||||
normalize(config) {
|
||||
if (Array.isArray(config)) {
|
||||
config = { plugins: config }
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// Apply default plugins
|
||||
if (isPureObject(config)) {
|
||||
config = Object.assign(
|
||||
{
|
||||
useConfigFile: false,
|
||||
sourceMap: this.options.build.cssSourceMap,
|
||||
plugins: {
|
||||
// https://github.com/postcss/postcss-import
|
||||
'postcss-import': {
|
||||
resolve: createResolver({
|
||||
alias: {
|
||||
'~': path.join(this.options.srcDir),
|
||||
'~~': path.join(this.options.rootDir),
|
||||
'@': path.join(this.options.srcDir),
|
||||
'@@': path.join(this.options.rootDir)
|
||||
},
|
||||
modules: [
|
||||
this.options.srcDir,
|
||||
this.options.rootDir,
|
||||
...this.options.modulesDir
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
// https://github.com/postcss/postcss-url
|
||||
'postcss-url': {},
|
||||
|
||||
// http://cssnext.io/postcss
|
||||
'postcss-cssnext': {}
|
||||
}
|
||||
},
|
||||
config
|
||||
)
|
||||
loadPlugins(config) {
|
||||
const plugins = config.plugins
|
||||
if (isPureObject(plugins)) {
|
||||
// Map postcss plugins into instances on object mode once
|
||||
config.plugins = Object.keys(plugins)
|
||||
.map(p => {
|
||||
const plugin = this.nuxt.requireModule(p)
|
||||
const opts = plugins[p]
|
||||
if (opts === false) return // Disabled
|
||||
const instance = plugin(opts)
|
||||
return instance
|
||||
})
|
||||
.filter(e => e)
|
||||
}
|
||||
}
|
||||
|
||||
// Map postcss plugins into instances on object mode once
|
||||
if (isPureObject(config) && isPureObject(config.plugins)) {
|
||||
config.plugins = Object.keys(config.plugins)
|
||||
.map(p => {
|
||||
const plugin = this.nuxt.requireModule(p)
|
||||
const opts = config.plugins[p]
|
||||
if (opts === false) return // Disabled
|
||||
const instance = plugin(opts)
|
||||
return instance
|
||||
})
|
||||
.filter(e => e)
|
||||
}
|
||||
config() {
|
||||
/* istanbul ignore if */
|
||||
if (!this.postcss) {
|
||||
return false
|
||||
}
|
||||
|
||||
return config
|
||||
let config = this.configFromFile()
|
||||
if (config) {
|
||||
return config
|
||||
}
|
||||
|
||||
config = this.normalize(ـ.cloneDeep(this.postcss))
|
||||
|
||||
// Apply default plugins
|
||||
if (isPureObject(config)) {
|
||||
config = ـ.defaults(config, this.defaultConfig)
|
||||
|
||||
this.loadPlugins(config)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
}
|
||||
|
@ -2,88 +2,119 @@ import path from 'path'
|
||||
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
||||
|
||||
import postcssConfig from './postcss'
|
||||
import PostcssConfig from './postcss'
|
||||
|
||||
export default ({ isServer }) => {
|
||||
return function styleLoader(ext, loaders = []) {
|
||||
const sourceMap = Boolean(this.options.build.cssSourceMap)
|
||||
export default class StyleLoader {
|
||||
constructor(options, nuxt, { isServer }) {
|
||||
this.isServer = isServer
|
||||
this.dev = options.dev
|
||||
this.srcDir = options.srcDir
|
||||
this.assetsDir = options.dir.assets
|
||||
this.staticDir = options.dir.static
|
||||
this.extractCSS = options.build.extractCSS
|
||||
this.resources = options.build.styleResources
|
||||
this.sourceMap = Boolean(options.build.cssSourceMap)
|
||||
|
||||
// Normalize loaders
|
||||
loaders = (Array.isArray(loaders) ? loaders : [loaders]).map(loader =>
|
||||
Object.assign(
|
||||
{ options: { sourceMap } },
|
||||
typeof loader === 'string' ? { loader } : loader
|
||||
)
|
||||
)
|
||||
if (options.build.postcss) {
|
||||
this.postcssConfig = new PostcssConfig(options, nuxt)
|
||||
}
|
||||
}
|
||||
|
||||
// -- Configure additional loaders --
|
||||
normalize(loaders) {
|
||||
loaders = Array.isArray(loaders) ? loaders : [loaders]
|
||||
return loaders.map(loader => Object.assign(
|
||||
{ options: { sourceMap: this.sourceMap } },
|
||||
typeof loader === 'string' ? { loader } : loader
|
||||
))
|
||||
}
|
||||
|
||||
styleResource(ext, loaders) {
|
||||
const extResource = this.resources[ext]
|
||||
// style-resources-loader
|
||||
// https://github.com/yenshih/style-resources-loader
|
||||
if (this.options.build.styleResources[ext]) {
|
||||
const patterns = Array.isArray(this.options.build.styleResources[ext])
|
||||
? this.options.build.styleResources[ext]
|
||||
: [this.options.build.styleResources[ext]]
|
||||
const options = Object.assign(
|
||||
{},
|
||||
this.options.build.styleResources.options || {},
|
||||
{ patterns }
|
||||
)
|
||||
if (extResource) {
|
||||
const patterns = Array.isArray(extResource)
|
||||
? extResource
|
||||
: [extResource]
|
||||
|
||||
loaders.push({
|
||||
loader: 'style-resources-loader',
|
||||
options
|
||||
options: Object.assign(
|
||||
{ patterns },
|
||||
this.resources.options || {}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
postcss(loaders) {
|
||||
// postcss-loader
|
||||
// https://github.com/postcss/postcss-loader
|
||||
const _postcssConfig = postcssConfig.call(this)
|
||||
|
||||
if (_postcssConfig) {
|
||||
loaders.unshift({
|
||||
loader: 'postcss-loader',
|
||||
options: Object.assign({ sourceMap }, _postcssConfig)
|
||||
})
|
||||
if (this.postcssConfig) {
|
||||
const config = this.postcssConfig.config()
|
||||
if (config) {
|
||||
loaders.unshift({
|
||||
loader: 'postcss-loader',
|
||||
options: Object.assign({ sourceMap: this.sourceMap }, config)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
css(loaders) {
|
||||
// css-loader
|
||||
// https://github.com/webpack-contrib/css-loader
|
||||
const cssLoaderAlias = {}
|
||||
cssLoaderAlias[`/${this.options.dir.assets}`] = path.join(this.options.srcDir, this.options.dir.assets)
|
||||
cssLoaderAlias[`/${this.options.dir.static}`] = path.join(this.options.srcDir, this.options.dir.static)
|
||||
const cssLoaderAlias = {
|
||||
[`/${this.assetsDir}`]: path.join(this.srcDir, this.assetsDir),
|
||||
[`/${this.staticDir}`]: path.join(this.srcDir, this.staticDir)
|
||||
}
|
||||
|
||||
loaders.unshift({
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap,
|
||||
minimize: !this.options.dev,
|
||||
sourceMap: this.sourceMap,
|
||||
minimize: !this.dev,
|
||||
importLoaders: loaders.length, // Important!
|
||||
alias: cssLoaderAlias
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// -- With extractCSS --
|
||||
if (this.options.build.extractCSS) {
|
||||
if (!isServer) {
|
||||
loaders.unshift(MiniCssExtractPlugin.loader)
|
||||
if (this.options.dev) {
|
||||
// css-hot-loader
|
||||
// https://github.com/shepherdwind/css-hot-loader
|
||||
loaders.unshift({
|
||||
loader: 'css-hot-loader',
|
||||
options: { sourceMap }
|
||||
})
|
||||
}
|
||||
extract(loaders) {
|
||||
if (this.extractCSS && !this.isServer) {
|
||||
loaders.unshift(MiniCssExtractPlugin.loader)
|
||||
if (this.dev) {
|
||||
// css-hot-loader
|
||||
// https://github.com/shepherdwind/css-hot-loader
|
||||
loaders.unshift({
|
||||
loader: 'css-hot-loader',
|
||||
options: { sourceMap: this.sourceMap }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Prepare vue-style-loader
|
||||
// https://github.com/vuejs/vue-style-loader
|
||||
loaders.unshift({
|
||||
loader: 'vue-style-loader',
|
||||
options: { sourceMap }
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
vueStyle(loaders) {
|
||||
// https://github.com/vuejs/vue-style-loader
|
||||
loaders.unshift({
|
||||
loader: 'vue-style-loader',
|
||||
options: { sourceMap: this.sourceMap }
|
||||
})
|
||||
}
|
||||
|
||||
apply(ext, loaders = []) {
|
||||
// Normalize loaders
|
||||
loaders = this.normalize(loaders)
|
||||
|
||||
// -- Configure additional loaders --
|
||||
this.styleResource(ext, loaders)
|
||||
this.postcss(loaders)
|
||||
this.css(loaders)
|
||||
if (!this.extract(loaders)) {
|
||||
this.vueStyle(loaders)
|
||||
}
|
||||
|
||||
return loaders
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user