mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
refactor(schema,vite,webpack): rework postcss
module loading (#27946)
Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
parent
20dc6e5030
commit
4391381c61
@ -59,9 +59,11 @@
|
|||||||
"@vitejs/plugin-vue": "5.0.5",
|
"@vitejs/plugin-vue": "5.0.5",
|
||||||
"@vitest/coverage-v8": "1.6.0",
|
"@vitest/coverage-v8": "1.6.0",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.6",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
"case-police": "0.6.1",
|
"case-police": "0.6.1",
|
||||||
"changelogen": "0.5.5",
|
"changelogen": "0.5.5",
|
||||||
"consola": "3.2.3",
|
"consola": "3.2.3",
|
||||||
|
"cssnano": "^7.0.3",
|
||||||
"devalue": "5.0.0",
|
"devalue": "5.0.0",
|
||||||
"eslint": "9.6.0",
|
"eslint": "9.6.0",
|
||||||
"eslint-plugin-no-only-tests": "3.1.0",
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
|
@ -23,6 +23,8 @@ export default defineBuildConfig({
|
|||||||
externals: [
|
externals: [
|
||||||
// Type imports
|
// Type imports
|
||||||
'#app/components/nuxt-link',
|
'#app/components/nuxt-link',
|
||||||
|
'cssnano',
|
||||||
|
'autoprefixer',
|
||||||
'ofetch',
|
'ofetch',
|
||||||
'vue-router',
|
'vue-router',
|
||||||
'@nuxt/telemetry',
|
'@nuxt/telemetry',
|
||||||
|
@ -1,12 +1,45 @@
|
|||||||
import { defineUntypedSchema } from 'untyped'
|
import { defineUntypedSchema } from 'untyped'
|
||||||
|
|
||||||
|
const ensureItemIsLast = (item: string) => (arr: string[]) => {
|
||||||
|
const index = arr.indexOf(item)
|
||||||
|
if (index !== -1) {
|
||||||
|
arr.splice(index, 1)
|
||||||
|
arr.push(item)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderPresets = {
|
||||||
|
cssnanoLast: ensureItemIsLast('cssnano'),
|
||||||
|
autoprefixerLast: ensureItemIsLast('autoprefixer'),
|
||||||
|
autoprefixerAndCssnanoLast (names: string[]) {
|
||||||
|
return orderPresets.cssnanoLast(orderPresets.autoprefixerLast(names))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default defineUntypedSchema({
|
export default defineUntypedSchema({
|
||||||
postcss: {
|
postcss: {
|
||||||
|
/**
|
||||||
|
* A strategy for ordering PostCSS plugins.
|
||||||
|
*
|
||||||
|
* @type {'cssnanoLast' | 'autoprefixerLast' | 'autoprefixerAndCssnanoLast' | string[] | ((names: string[]) => string[])}
|
||||||
|
*/
|
||||||
|
order: {
|
||||||
|
$resolve: (val: string | string[] | ((plugins: string[]) => string[])): string[] | ((plugins: string[]) => string[]) => {
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
if (!(val in orderPresets)) {
|
||||||
|
throw new Error(`[nuxt] Unknown PostCSS order preset: ${val}`)
|
||||||
|
}
|
||||||
|
return orderPresets[val as keyof typeof orderPresets]
|
||||||
|
}
|
||||||
|
return val ?? orderPresets.autoprefixerAndCssnanoLast
|
||||||
|
},
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Options for configuring PostCSS plugins.
|
* Options for configuring PostCSS plugins.
|
||||||
*
|
*
|
||||||
* https://postcss.org/
|
* https://postcss.org/
|
||||||
* @type {Record<string, any> & { autoprefixer?: any; cssnano?: any }}
|
* @type {Record<string, Record<string, unknown> | false> & { autoprefixer?: typeof import('autoprefixer').Options; cssnano?: typeof import('cssnano').Options }}
|
||||||
*/
|
*/
|
||||||
plugins: {
|
plugins: {
|
||||||
/**
|
/**
|
||||||
|
@ -75,9 +75,10 @@ export interface NuxtBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normalized Nuxt options available as `nuxt.options.*`
|
// Normalized Nuxt options available as `nuxt.options.*`
|
||||||
export interface NuxtOptions extends Omit<ConfigSchema, 'builder' | 'webpack'> {
|
export interface NuxtOptions extends Omit<ConfigSchema, 'builder' | 'webpack' | 'postcss'> {
|
||||||
sourcemap: Required<Exclude<ConfigSchema['sourcemap'], boolean>>
|
sourcemap: Required<Exclude<ConfigSchema['sourcemap'], boolean>>
|
||||||
builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | NuxtBuilder
|
builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | NuxtBuilder
|
||||||
|
postcss: Omit<ConfigSchema['postcss'], 'order'> & { order: Exclude<ConfigSchema['postcss']['order'], string> }
|
||||||
webpack: ConfigSchema['webpack'] & {
|
webpack: ConfigSchema['webpack'] & {
|
||||||
$client: ConfigSchema['webpack']
|
$client: ConfigSchema['webpack']
|
||||||
$server: ConfigSchema['webpack']
|
$server: ConfigSchema['webpack']
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { requireModule } from '@nuxt/kit'
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||||
import type { Nuxt } from '@nuxt/schema'
|
import { requireModule, tryResolveModule } from '@nuxt/kit'
|
||||||
|
import type { Nuxt, NuxtOptions } from '@nuxt/schema'
|
||||||
import type { InlineConfig as ViteConfig } from 'vite'
|
import type { InlineConfig as ViteConfig } from 'vite'
|
||||||
import { distDir } from './dirs'
|
import { interopDefault } from 'mlly'
|
||||||
|
import type { Plugin } from 'postcss'
|
||||||
|
|
||||||
const lastPlugins = ['autoprefixer', 'cssnano']
|
function sortPlugins ({ plugins, order }: NuxtOptions['postcss']): string[] {
|
||||||
|
const names = Object.keys(plugins)
|
||||||
|
return typeof order === 'function' ? order(names) : (order || names)
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveCSSOptions (nuxt: Nuxt): ViteConfig['css'] {
|
export async function resolveCSSOptions (nuxt: Nuxt): Promise<ViteConfig['css']> {
|
||||||
const css: ViteConfig['css'] & { postcss: NonNullable<Exclude<NonNullable<ViteConfig['css']>['postcss'], string>> } = {
|
const css: ViteConfig['css'] & { postcss: NonNullable<Exclude<NonNullable<ViteConfig['css']>['postcss'], string>> } = {
|
||||||
postcss: {
|
postcss: {
|
||||||
plugins: [],
|
plugins: [],
|
||||||
@ -14,19 +19,26 @@ export function resolveCSSOptions (nuxt: Nuxt): ViteConfig['css'] {
|
|||||||
|
|
||||||
css.postcss.plugins = []
|
css.postcss.plugins = []
|
||||||
|
|
||||||
const plugins = Object.entries(nuxt.options.postcss.plugins)
|
const postcssOptions = nuxt.options.postcss
|
||||||
.sort((a, b) => lastPlugins.indexOf(a[0]) - lastPlugins.indexOf(b[0]))
|
|
||||||
|
|
||||||
for (const [name, opts] of plugins) {
|
const cwd = fileURLToPath(new URL('.', import.meta.url))
|
||||||
if (opts) {
|
for (const pluginName of sortPlugins(postcssOptions)) {
|
||||||
// TODO: remove use of requireModule in favour of ESM import
|
const pluginOptions = postcssOptions.plugins[pluginName]
|
||||||
const plugin = requireModule(name, {
|
if (!pluginOptions) { continue }
|
||||||
paths: [
|
|
||||||
...nuxt.options.modulesDir,
|
const path = await tryResolveModule(pluginName, nuxt.options.modulesDir)
|
||||||
distDir,
|
|
||||||
],
|
let pluginFn: (opts: Record<string, any>) => Plugin
|
||||||
})
|
// TODO: use jiti v2
|
||||||
css.postcss.plugins.push(plugin(opts))
|
if (path) {
|
||||||
|
pluginFn = await import(pathToFileURL(path).href).then(interopDefault)
|
||||||
|
} else {
|
||||||
|
console.warn(`[nuxt] could not import postcss plugin \`${pluginName}\` with ESM. Please report this as a bug.`)
|
||||||
|
// fall back to cjs
|
||||||
|
pluginFn = requireModule(pluginName, { paths: [cwd] })
|
||||||
|
}
|
||||||
|
if (typeof pluginFn === 'function') {
|
||||||
|
css.postcss.plugins.push(pluginFn(pluginOptions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import { composableKeysPlugin } from './plugins/composable-keys'
|
|||||||
import { logLevelMap } from './utils/logger'
|
import { logLevelMap } from './utils/logger'
|
||||||
import { ssrStylesPlugin } from './plugins/ssr-styles'
|
import { ssrStylesPlugin } from './plugins/ssr-styles'
|
||||||
import { VitePublicDirsPlugin } from './plugins/public-dirs'
|
import { VitePublicDirsPlugin } from './plugins/public-dirs'
|
||||||
|
import { distDir } from './dirs'
|
||||||
|
|
||||||
export interface ViteBuildContext {
|
export interface ViteBuildContext {
|
||||||
nuxt: Nuxt
|
nuxt: Nuxt
|
||||||
@ -33,6 +34,8 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
|||||||
(nuxt.options.vite.devBundler === 'vite-node' && nuxt.options.dev)
|
(nuxt.options.vite.devBundler === 'vite-node' && nuxt.options.dev)
|
||||||
const entry = await resolvePath(resolve(nuxt.options.appDir, useAsyncEntry ? 'entry.async' : 'entry'))
|
const entry = await resolvePath(resolve(nuxt.options.appDir, useAsyncEntry ? 'entry.async' : 'entry'))
|
||||||
|
|
||||||
|
nuxt.options.modulesDir.push(distDir)
|
||||||
|
|
||||||
let allowDirs = [
|
let allowDirs = [
|
||||||
nuxt.options.appDir,
|
nuxt.options.appDir,
|
||||||
nuxt.options.workspaceDir,
|
nuxt.options.workspaceDir,
|
||||||
@ -72,7 +75,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
|||||||
'abort-controller': 'unenv/runtime/mock/empty',
|
'abort-controller': 'unenv/runtime/mock/empty',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
css: resolveCSSOptions(nuxt),
|
css: await resolveCSSOptions(nuxt),
|
||||||
define: {
|
define: {
|
||||||
__NUXT_VERSION__: JSON.stringify(nuxt._version),
|
__NUXT_VERSION__: JSON.stringify(nuxt._version),
|
||||||
__NUXT_ASYNC_CONTEXT__: nuxt.options.experimental.asyncContext,
|
__NUXT_ASYNC_CONTEXT__: nuxt.options.experimental.asyncContext,
|
||||||
|
@ -11,11 +11,11 @@ import type { WebpackConfigContext } from '../utils/config'
|
|||||||
import { applyPresets } from '../utils/config'
|
import { applyPresets } from '../utils/config'
|
||||||
import { nuxt } from '../presets/nuxt'
|
import { nuxt } from '../presets/nuxt'
|
||||||
|
|
||||||
export function client (ctx: WebpackConfigContext) {
|
export async function client (ctx: WebpackConfigContext) {
|
||||||
ctx.name = 'client'
|
ctx.name = 'client'
|
||||||
ctx.isClient = true
|
ctx.isClient = true
|
||||||
|
|
||||||
applyPresets(ctx, [
|
await applyPresets(ctx, [
|
||||||
nuxt,
|
nuxt,
|
||||||
clientPlugins,
|
clientPlugins,
|
||||||
clientOptimization,
|
clientOptimization,
|
||||||
|
@ -9,11 +9,11 @@ import { node } from '../presets/node'
|
|||||||
|
|
||||||
const assetPattern = /\.(?:css|s[ca]ss|png|jpe?g|gif|svg|woff2?|eot|ttf|otf|webp|webm|mp4|ogv)(?:\?.*)?$/i
|
const assetPattern = /\.(?:css|s[ca]ss|png|jpe?g|gif|svg|woff2?|eot|ttf|otf|webp|webm|mp4|ogv)(?:\?.*)?$/i
|
||||||
|
|
||||||
export function server (ctx: WebpackConfigContext) {
|
export async function server (ctx: WebpackConfigContext) {
|
||||||
ctx.name = 'server'
|
ctx.name = 'server'
|
||||||
ctx.isServer = true
|
ctx.isServer = true
|
||||||
|
|
||||||
applyPresets(ctx, [
|
await applyPresets(ctx, [
|
||||||
nuxt,
|
nuxt,
|
||||||
node,
|
node,
|
||||||
serverStandalone,
|
serverStandalone,
|
||||||
|
@ -16,8 +16,8 @@ import WarningIgnorePlugin from '../plugins/warning-ignore'
|
|||||||
import type { WebpackConfigContext } from '../utils/config'
|
import type { WebpackConfigContext } from '../utils/config'
|
||||||
import { applyPresets, fileName } from '../utils/config'
|
import { applyPresets, fileName } from '../utils/config'
|
||||||
|
|
||||||
export function base (ctx: WebpackConfigContext) {
|
export async function base (ctx: WebpackConfigContext) {
|
||||||
applyPresets(ctx, [
|
await applyPresets(ctx, [
|
||||||
baseAlias,
|
baseAlias,
|
||||||
baseConfig,
|
baseConfig,
|
||||||
basePlugins,
|
basePlugins,
|
||||||
|
@ -8,8 +8,8 @@ import { pug } from './pug'
|
|||||||
import { style } from './style'
|
import { style } from './style'
|
||||||
import { vue } from './vue'
|
import { vue } from './vue'
|
||||||
|
|
||||||
export function nuxt (ctx: WebpackConfigContext) {
|
export async function nuxt (ctx: WebpackConfigContext) {
|
||||||
applyPresets(ctx, [
|
await applyPresets(ctx, [
|
||||||
base,
|
base,
|
||||||
assets,
|
assets,
|
||||||
esbuild,
|
esbuild,
|
||||||
|
@ -4,8 +4,8 @@ import type { WebpackConfigContext } from '../utils/config'
|
|||||||
import { applyPresets, fileName } from '../utils/config'
|
import { applyPresets, fileName } from '../utils/config'
|
||||||
import { getPostcssConfig } from '../utils/postcss'
|
import { getPostcssConfig } from '../utils/postcss'
|
||||||
|
|
||||||
export function style (ctx: WebpackConfigContext) {
|
export async function style (ctx: WebpackConfigContext) {
|
||||||
applyPresets(ctx, [
|
await applyPresets(ctx, [
|
||||||
loaders,
|
loaders,
|
||||||
extractCSS,
|
extractCSS,
|
||||||
minimizer,
|
minimizer,
|
||||||
@ -32,32 +32,32 @@ function extractCSS (ctx: WebpackConfigContext) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function loaders (ctx: WebpackConfigContext) {
|
async function loaders (ctx: WebpackConfigContext) {
|
||||||
// CSS
|
// CSS
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('css', /\.css$/i, null, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('css', /\.css$/i, null, ctx))
|
||||||
|
|
||||||
// PostCSS
|
// PostCSS
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
|
||||||
|
|
||||||
// Less
|
// Less
|
||||||
const lessLoader = { loader: 'less-loader', options: ctx.userConfig.loaders.less }
|
const lessLoader = { loader: 'less-loader', options: ctx.userConfig.loaders.less }
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('less', /\.less$/i, lessLoader, ctx))
|
||||||
|
|
||||||
// Sass (TODO: optional dependency)
|
// Sass (TODO: optional dependency)
|
||||||
const sassLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.sass }
|
const sassLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.sass }
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
|
||||||
|
|
||||||
const scssLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.scss }
|
const scssLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.scss }
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
|
||||||
|
|
||||||
// Stylus
|
// Stylus
|
||||||
const stylusLoader = { loader: 'stylus-loader', options: ctx.userConfig.loaders.stylus }
|
const stylusLoader = { loader: 'stylus-loader', options: ctx.userConfig.loaders.stylus }
|
||||||
ctx.config.module!.rules!.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
|
ctx.config.module!.rules!.push(await createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx: WebpackConfigContext) {
|
async function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx: WebpackConfigContext) {
|
||||||
const styleLoaders = [
|
const styleLoaders = [
|
||||||
createPostcssLoadersRule(ctx),
|
await createPostcssLoadersRule(ctx),
|
||||||
processorLoader,
|
processorLoader,
|
||||||
].filter(Boolean)
|
].filter(Boolean)
|
||||||
|
|
||||||
@ -114,10 +114,10 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any)
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPostcssLoadersRule (ctx: WebpackConfigContext) {
|
async function createPostcssLoadersRule (ctx: WebpackConfigContext) {
|
||||||
if (!ctx.options.postcss) { return }
|
if (!ctx.options.postcss) { return }
|
||||||
|
|
||||||
const config = getPostcssConfig(ctx.nuxt)
|
const config = await getPostcssConfig(ctx.nuxt)
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return
|
return
|
||||||
|
@ -17,7 +17,7 @@ export interface WebpackConfigContext {
|
|||||||
transpile: RegExp[]
|
transpile: RegExp[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebpackConfigPreset = (ctx: WebpackConfigContext, options?: object) => void
|
type WebpackConfigPreset = (ctx: WebpackConfigContext, options?: object) => void | Promise<void>
|
||||||
type WebpackConfigPresetItem = WebpackConfigPreset | [WebpackConfigPreset, any]
|
type WebpackConfigPresetItem = WebpackConfigPreset | [WebpackConfigPreset, any]
|
||||||
|
|
||||||
export function createWebpackConfigContext (nuxt: Nuxt): WebpackConfigContext {
|
export function createWebpackConfigContext (nuxt: Nuxt): WebpackConfigContext {
|
||||||
@ -37,12 +37,12 @@ export function createWebpackConfigContext (nuxt: Nuxt): WebpackConfigContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigPresetItem | WebpackConfigPresetItem[]) {
|
export async function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigPresetItem | WebpackConfigPresetItem[]) {
|
||||||
for (const preset of toArray(presets)) {
|
for (const preset of toArray(presets)) {
|
||||||
if (Array.isArray(preset)) {
|
if (Array.isArray(preset)) {
|
||||||
preset[0](ctx, preset[1])
|
await preset[0](ctx, preset[1])
|
||||||
} else {
|
} else {
|
||||||
preset(ctx)
|
await preset(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,19 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||||
import createResolver from 'postcss-import-resolver'
|
import createResolver from 'postcss-import-resolver'
|
||||||
import { requireModule } from '@nuxt/kit'
|
import { interopDefault } from 'mlly'
|
||||||
import type { Nuxt } from '@nuxt/schema'
|
import { requireModule, tryResolveModule } from '@nuxt/kit'
|
||||||
|
import type { Nuxt, NuxtOptions } from '@nuxt/schema'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
|
import type { Plugin } from 'postcss'
|
||||||
|
|
||||||
const isPureObject = (obj: unknown): obj is Object => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
|
const isPureObject = (obj: unknown): obj is Object => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
|
||||||
|
|
||||||
const ensureItemIsLast = (item: string) => (arr: string[]) => {
|
function sortPlugins ({ plugins, order }: NuxtOptions['postcss']): string[] {
|
||||||
const index = arr.indexOf(item)
|
const names = Object.keys(plugins)
|
||||||
if (index !== -1) {
|
return typeof order === 'function' ? order(names) : (order || names)
|
||||||
arr.splice(index, 1)
|
|
||||||
arr.push(item)
|
|
||||||
}
|
|
||||||
return arr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderPresets = {
|
export async function getPostcssConfig (nuxt: Nuxt) {
|
||||||
cssnanoLast: ensureItemIsLast('cssnano'),
|
|
||||||
autoprefixerLast: ensureItemIsLast('autoprefixer'),
|
|
||||||
autoprefixerAndCssnanoLast (names: string[]) {
|
|
||||||
return orderPresets.cssnanoLast(orderPresets.autoprefixerLast(names))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getPostcssConfig = (nuxt: Nuxt) => {
|
|
||||||
function sortPlugins ({ plugins, order }: any) {
|
|
||||||
const names = Object.keys(plugins)
|
|
||||||
if (typeof order === 'string') {
|
|
||||||
order = orderPresets[order as keyof typeof orderPresets]
|
|
||||||
}
|
|
||||||
return typeof order === 'function' ? order(names, orderPresets) : (order || names)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nuxt.options.webpack.postcss || !nuxt.options.postcss) {
|
if (!nuxt.options.webpack.postcss || !nuxt.options.postcss) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -54,21 +36,35 @@ export const getPostcssConfig = (nuxt: Nuxt) => {
|
|||||||
'postcss-url': {},
|
'postcss-url': {},
|
||||||
},
|
},
|
||||||
sourceMap: nuxt.options.webpack.cssSourceMap,
|
sourceMap: nuxt.options.webpack.cssSourceMap,
|
||||||
// Array, String or Function
|
|
||||||
order: 'autoprefixerAndCssnanoLast',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Keep the order of default plugins
|
// Keep the order of default plugins
|
||||||
if (!Array.isArray(postcssOptions.plugins) && isPureObject(postcssOptions.plugins)) {
|
if (!Array.isArray(postcssOptions.plugins) && isPureObject(postcssOptions.plugins)) {
|
||||||
// Map postcss plugins into instances on object mode once
|
// Map postcss plugins into instances on object mode once
|
||||||
const cwd = fileURLToPath(new URL('.', import.meta.url))
|
const cwd = fileURLToPath(new URL('.', import.meta.url))
|
||||||
postcssOptions.plugins = sortPlugins(postcssOptions).map((pluginName: string) => {
|
const plugins: Plugin[] = []
|
||||||
// TODO: remove use of requireModule in favour of ESM import
|
for (const pluginName of sortPlugins(postcssOptions)) {
|
||||||
const pluginFn = requireModule(pluginName, { paths: [cwd] })
|
|
||||||
const pluginOptions = postcssOptions.plugins[pluginName]
|
const pluginOptions = postcssOptions.plugins[pluginName]
|
||||||
if (!pluginOptions || typeof pluginFn !== 'function') { return null }
|
if (!pluginOptions) { continue }
|
||||||
return pluginFn(pluginOptions)
|
|
||||||
}).filter(Boolean)
|
const path = await tryResolveModule(pluginName, nuxt.options.modulesDir)
|
||||||
|
|
||||||
|
let pluginFn: (opts: Record<string, any>) => Plugin
|
||||||
|
// TODO: use jiti v2
|
||||||
|
if (path) {
|
||||||
|
pluginFn = await import(pathToFileURL(path).href).then(interopDefault)
|
||||||
|
} else {
|
||||||
|
console.warn(`[nuxt] could not import postcss plugin \`${pluginName}\` with ESM. Please report this as a bug.`)
|
||||||
|
// fall back to cjs
|
||||||
|
pluginFn = requireModule(pluginName, { paths: [cwd] })
|
||||||
|
}
|
||||||
|
if (typeof pluginFn === 'function') {
|
||||||
|
plugins.push(pluginFn(pluginOptions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error we are mutating type here from object to array
|
||||||
|
postcssOptions.plugins = plugins
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -25,12 +25,12 @@ import { applyPresets, createWebpackConfigContext, getWebpackConfig } from './ut
|
|||||||
export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
||||||
registerVirtualModules()
|
registerVirtualModules()
|
||||||
|
|
||||||
const webpackConfigs = [client, ...nuxt.options.ssr ? [server] : []].map((preset) => {
|
const webpackConfigs = await Promise.all([client, ...nuxt.options.ssr ? [server] : []].map(async (preset) => {
|
||||||
const ctx = createWebpackConfigContext(nuxt)
|
const ctx = createWebpackConfigContext(nuxt)
|
||||||
ctx.userConfig = defu(nuxt.options.webpack[`$${preset.name as 'client' | 'server'}`], ctx.userConfig)
|
ctx.userConfig = defu(nuxt.options.webpack[`$${preset.name as 'client' | 'server'}`], ctx.userConfig)
|
||||||
applyPresets(ctx, preset)
|
await applyPresets(ctx, preset)
|
||||||
return getWebpackConfig(ctx)
|
return getWebpackConfig(ctx)
|
||||||
})
|
}))
|
||||||
|
|
||||||
await nuxt.callHook('webpack:config', webpackConfigs)
|
await nuxt.callHook('webpack:config', webpackConfigs)
|
||||||
|
|
||||||
|
@ -59,6 +59,9 @@ importers:
|
|||||||
'@vue/test-utils':
|
'@vue/test-utils':
|
||||||
specifier: 2.4.6
|
specifier: 2.4.6
|
||||||
version: 2.4.6
|
version: 2.4.6
|
||||||
|
autoprefixer:
|
||||||
|
specifier: ^10.4.19
|
||||||
|
version: 10.4.19(postcss@8.4.39)
|
||||||
case-police:
|
case-police:
|
||||||
specifier: 0.6.1
|
specifier: 0.6.1
|
||||||
version: 0.6.1
|
version: 0.6.1
|
||||||
@ -68,6 +71,9 @@ importers:
|
|||||||
consola:
|
consola:
|
||||||
specifier: 3.2.3
|
specifier: 3.2.3
|
||||||
version: 3.2.3
|
version: 3.2.3
|
||||||
|
cssnano:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3(postcss@8.4.39)
|
||||||
devalue:
|
devalue:
|
||||||
specifier: 5.0.0
|
specifier: 5.0.0
|
||||||
version: 5.0.0
|
version: 5.0.0
|
||||||
|
Loading…
Reference in New Issue
Block a user