mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 13:45:18 +00:00
feat(style): add style loaders (#50)
* feat(style): add style loaders * refactor: merge utils/style-loader to style preset * refactor style.ts Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
db050fd0a2
commit
232d3298b4
@ -285,10 +285,10 @@ export default () => ({
|
|||||||
vueStyle: {}
|
vueStyle: {}
|
||||||
} as Loaders,
|
} as Loaders,
|
||||||
loadingScreen: {} as Record<string, any> | false,
|
loadingScreen: {} as Record<string, any> | false,
|
||||||
|
optimizeCSS: undefined as Record<string, any> | false | undefined,
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: undefined as boolean | undefined,
|
minimize: undefined as boolean | undefined,
|
||||||
minimizer: undefined,
|
minimizer: undefined,
|
||||||
// cssMinimizer: undefined,
|
|
||||||
splitChunks: {
|
splitChunks: {
|
||||||
chunks: 'all',
|
chunks: 'all',
|
||||||
name: undefined,
|
name: undefined,
|
||||||
@ -298,9 +298,7 @@ export default () => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} as WebpackConfiguration['optimization'] & {
|
} as WebpackConfiguration['optimization'],
|
||||||
// cssMinimizer: undefined | boolean | Record<string, any>
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) in webpack building
|
* Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) in webpack building
|
||||||
*
|
*
|
||||||
|
@ -345,10 +345,9 @@ function normalizeConfig (_options: CliConfiguration) {
|
|||||||
options.build.optimization.minimize = !options.dev
|
options.build.optimization.minimize = !options.dev
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable cssMinimizer only when extractCSS is enabled
|
if (options.build.optimizeCSS === undefined) {
|
||||||
// if (options.build.optimization.cssMinimizer === undefined) {
|
options.build.optimizeCSS = options.build.extractCSS ? {} : false
|
||||||
// options.build.optimization.cssMinimizer = options.build.extractCSS ? {} : false
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
const { loaders } = options.build
|
const { loaders } = options.build
|
||||||
// const vueLoader = loaders.vue
|
// const vueLoader = loaders.vue
|
||||||
|
@ -1,62 +1,136 @@
|
|||||||
// import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
import path from 'path'
|
||||||
// import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
||||||
// import StyleLoader from '../utils/style-loader'
|
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
|
||||||
|
import { wrapArray } from 'src/utils'
|
||||||
|
import { fileName, WebpackConfigContext, applyPresets } from '../utils/config'
|
||||||
|
|
||||||
import { WebpackConfigContext } from '../utils/config'
|
export function style (ctx: WebpackConfigContext) {
|
||||||
|
applyPresets(ctx, [
|
||||||
|
loaders,
|
||||||
|
extractCSS,
|
||||||
|
minimizer
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function minimizer (ctx: WebpackConfigContext) {
|
||||||
|
const { options, config } = ctx
|
||||||
|
|
||||||
|
if (options.build.optimizeCSS && Array.isArray(config.optimization.minimizer)) {
|
||||||
|
config.optimization.minimizer.push(new CssMinimizerPlugin({
|
||||||
|
...options.build.optimizeCSS
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractCSS (ctx: WebpackConfigContext) {
|
||||||
|
const { options, config } = ctx
|
||||||
|
|
||||||
export function style (_ctx: WebpackConfigContext) {
|
|
||||||
// // CSS extraction)
|
|
||||||
// if (options.build.extractCSS) {
|
|
||||||
// plugins.push(new MiniCssExtractPlugin(Object.assign({
|
|
||||||
// filename: fileName(ctx, 'css'),
|
|
||||||
// chunkFilename: fileName(ctx, 'css')
|
|
||||||
// }, options.build.extractCSS)))
|
|
||||||
// }
|
|
||||||
// CSS extraction
|
// CSS extraction
|
||||||
// if (options.build.extractCSS) {
|
if (options.build.extractCSS) {
|
||||||
// plugins.push(new MiniCssExtractPlugin(Object.assign({
|
config.plugins.push(new MiniCssExtractPlugin({
|
||||||
// filename: fileName(ctx, 'css'),
|
filename: fileName(ctx, 'css'),
|
||||||
// chunkFilename: fileName(ctx, 'css'),
|
chunkFilename: fileName(ctx, 'css'),
|
||||||
// // TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
|
...(options.build.extractCSS as object)
|
||||||
// reloadAll: true
|
}))
|
||||||
// }, options.build.extractCSS)))
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
function loaders (ctx: WebpackConfigContext) {
|
||||||
|
const { config, options } = ctx
|
||||||
|
|
||||||
|
// CSS
|
||||||
|
config.module.rules.push(createdStyleRule('css', /\.css$/i, null, ctx))
|
||||||
|
|
||||||
|
// Postcss
|
||||||
|
config.module.rules.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
|
||||||
|
|
||||||
|
// Less
|
||||||
|
const lessLoader = { loader: 'less-loader', options: options.build.loaders.less }
|
||||||
|
config.module.rules.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
|
||||||
|
|
||||||
|
// Sass (TODO: optional dependency)
|
||||||
|
const sassLoader = { loader: 'sass-loader', options: options.build.loaders.sass }
|
||||||
|
config.module.rules.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
|
||||||
|
|
||||||
|
const scssLoader = { loader: 'sass-loader', options: options.build.loaders.scss }
|
||||||
|
config.module.rules.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
|
||||||
|
|
||||||
|
// Stylus
|
||||||
|
const stylusLoader = { loader: 'stylus-loader', options: options.build.loaders.stylus }
|
||||||
|
config.module.rules.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
function createdStyleRule (lang: string, test: RegExp, processorLoader, ctx: WebpackConfigContext) {
|
||||||
|
const { options } = ctx
|
||||||
|
|
||||||
|
const styleLoaders = [
|
||||||
|
processorLoader,
|
||||||
|
createStyleResourcesLoaderRule(lang, options.build.styleResources, options.rootDir)
|
||||||
|
].filter(Boolean)
|
||||||
|
|
||||||
|
options.build.loaders.css.importLoaders =
|
||||||
|
options.build.loaders.cssModules.importLoaders =
|
||||||
|
styleLoaders.length
|
||||||
|
|
||||||
|
const cssLoaders = createCssLoadersRule(ctx, options.build.loaders.css)
|
||||||
|
const cssModuleLoaders = createCssLoadersRule(ctx, options.build.loaders.cssModules)
|
||||||
|
|
||||||
|
return {
|
||||||
|
test,
|
||||||
|
oneOf: [
|
||||||
|
// This matches <style module>
|
||||||
|
{
|
||||||
|
resourceQuery: /module/,
|
||||||
|
use: cssModuleLoaders.concat(styleLoaders)
|
||||||
|
},
|
||||||
|
// This matches plain <style> or <style scoped>
|
||||||
|
{
|
||||||
|
use: cssLoaders.concat(styleLoaders)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions) {
|
||||||
|
const { options } = ctx
|
||||||
|
|
||||||
|
const cssLoader = { loader: 'css-loader', options: cssLoaderOptions }
|
||||||
|
|
||||||
|
if (options.build.extractCSS) {
|
||||||
|
if (ctx.isServer) {
|
||||||
|
return [cssLoader]
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// {
|
{
|
||||||
// test: /\.css$/i,
|
loader: MiniCssExtractPlugin.loader,
|
||||||
// oneOf: styleLoader.apply('css')
|
options: { reloadAll: ctx.isDev, hot: ctx.isDev }
|
||||||
// },
|
},
|
||||||
// {
|
cssLoader
|
||||||
// test: /\.p(ost)?css$/i,
|
]
|
||||||
// oneOf: styleLoader.apply('postcss')
|
}
|
||||||
// },
|
|
||||||
// {
|
return [
|
||||||
// test: /\.less$/i,
|
{
|
||||||
// oneOf: styleLoader.apply('less', {
|
loader: 'vue-style-loader',
|
||||||
// loader: 'less-loader',
|
options: options.build.loaders.vueStyle
|
||||||
// options: loaders.less
|
},
|
||||||
// })
|
cssLoader
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// test: /\.sass$/i,
|
|
||||||
// oneOf: styleLoader.apply('sass', {
|
|
||||||
// loader: 'sass-loader',
|
|
||||||
// options: loaders.sass
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// test: /\.scss$/i,
|
|
||||||
// oneOf: styleLoader.apply('scss', {
|
|
||||||
// loader: 'sass-loader',
|
|
||||||
// options: loaders.scss
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// test: /\.styl(us)?$/i,
|
|
||||||
// oneOf: styleLoader.apply('stylus', {
|
|
||||||
// loader: 'stylus-loader',
|
|
||||||
// options: loaders.stylus
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createStyleResourcesLoaderRule (styleLang, styleResources, rootDir) {
|
||||||
|
// style-resources-loader
|
||||||
|
// https://github.com/yenshih/style-resources-loader
|
||||||
|
if (!styleResources[styleLang]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
loader: 'style-resources-loader',
|
||||||
|
options: {
|
||||||
|
patterns: wrapArray(styleResources[styleLang]).map(p => path.resolve(rootDir, p)),
|
||||||
|
...styleResources.options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,137 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
// import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin'
|
|
||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
|
||||||
|
|
||||||
import type { Nuxt } from 'src/core'
|
|
||||||
import type { NormalizedConfiguration } from 'src/config'
|
|
||||||
import { wrapArray } from 'src/utils'
|
|
||||||
|
|
||||||
import PostcssConfig from './postcss'
|
|
||||||
|
|
||||||
export default class StyleLoader {
|
|
||||||
options: NormalizedConfiguration
|
|
||||||
|
|
||||||
constructor (nuxt: Nuxt, { isServer }) {
|
|
||||||
this.options = nuxt.options
|
|
||||||
this.isServer = isServer
|
|
||||||
|
|
||||||
if (this.options.build.postcss) {
|
|
||||||
this.postcssConfig = new PostcssConfig(nuxt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get extractCSS () {
|
|
||||||
return this.options.build.extractCSS
|
|
||||||
}
|
|
||||||
|
|
||||||
normalize (loaders) {
|
|
||||||
loaders = wrapArray(loaders)
|
|
||||||
return loaders.map(loader => (typeof loader === 'string' ? { loader } : loader))
|
|
||||||
}
|
|
||||||
|
|
||||||
styleResource (ext) {
|
|
||||||
const { build: { styleResources }, rootDir } = this.options
|
|
||||||
const extResource = styleResources[ext]
|
|
||||||
// style-resources-loader
|
|
||||||
// https://github.com/yenshih/style-resources-loader
|
|
||||||
if (!extResource) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const patterns = wrapArray(extResource).map(p => path.resolve(rootDir, p))
|
|
||||||
|
|
||||||
return {
|
|
||||||
loader: 'style-resources-loader',
|
|
||||||
options: Object.assign(
|
|
||||||
{ patterns },
|
|
||||||
styleResources.options || {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
postcss () {
|
|
||||||
// postcss-loader
|
|
||||||
// https://github.com/postcss/postcss-loader
|
|
||||||
if (!this.postcssConfig) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = this.postcssConfig.config()
|
|
||||||
|
|
||||||
if (!config) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: Object.assign({ sourceMap: this.options.build.cssSourceMap }, config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
css (options) {
|
|
||||||
const cssLoader = { loader: 'css-loader', options }
|
|
||||||
|
|
||||||
if (this.isServer && this.extractCSS) {
|
|
||||||
options.modules = options.modules || {}
|
|
||||||
options.modules.exportOnlyLocals = true
|
|
||||||
return [cssLoader]
|
|
||||||
}
|
|
||||||
|
|
||||||
return [this.styleLoader(), cssLoader]
|
|
||||||
}
|
|
||||||
|
|
||||||
cssModules (options) {
|
|
||||||
return this.css(options)
|
|
||||||
}
|
|
||||||
|
|
||||||
extract () {
|
|
||||||
if (this.extractCSS) {
|
|
||||||
const isDev = this.options.dev
|
|
||||||
return {
|
|
||||||
loader: MiniCssExtractPlugin.loader,
|
|
||||||
options: {
|
|
||||||
// TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
|
|
||||||
// https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/161#issuecomment-500162574
|
|
||||||
reloadAll: isDev,
|
|
||||||
hot: isDev
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
styleLoader () {
|
|
||||||
return this.extract() || {
|
|
||||||
loader: 'vue-style-loader',
|
|
||||||
options: this.options.build.loaders.vueStyle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply (ext, loaders = []) {
|
|
||||||
const { css, cssModules } = this.options.build.loaders
|
|
||||||
|
|
||||||
const customLoaders = [].concat(
|
|
||||||
this.postcss(),
|
|
||||||
this.normalize(loaders),
|
|
||||||
this.styleResource(ext)
|
|
||||||
).filter(Boolean)
|
|
||||||
|
|
||||||
css.importLoaders = cssModules.importLoaders = customLoaders.length
|
|
||||||
|
|
||||||
return [
|
|
||||||
// This matches <style module>
|
|
||||||
{
|
|
||||||
resourceQuery: /module/,
|
|
||||||
use: [
|
|
||||||
this.cssModules(cssModules),
|
|
||||||
customLoaders
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// This matches plain <style> or <style scoped>
|
|
||||||
{
|
|
||||||
use: [
|
|
||||||
this.css(css),
|
|
||||||
customLoaders
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user