diff --git a/packages/webpack/src/configs/client.ts b/packages/webpack/src/configs/client.ts index 37b06bcc9c..6d8e3d59ee 100644 --- a/packages/webpack/src/configs/client.ts +++ b/packages/webpack/src/configs/client.ts @@ -1,8 +1,9 @@ import querystring from 'node:querystring' +import { pathToFileURL } from 'node:url' import { resolve } from 'pathe' import webpack from 'webpack' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' -import { logger } from '@nuxt/kit' +import { logger, tryResolveModule } from '@nuxt/kit' import { joinURL } from 'ufo' import ForkTSCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' @@ -46,7 +47,7 @@ function clientPerformance (ctx: WebpackConfigContext) { } } -function clientHMR (ctx: WebpackConfigContext) { +async function clientHMR (ctx: WebpackConfigContext) { if (!ctx.isDev) { return } @@ -65,9 +66,10 @@ function clientHMR (ctx: WebpackConfigContext) { // Add HMR support const app = (ctx.config.entry as any).app as any + const hotMiddlewarePath = await tryResolveModule('webpack-hot-middleware/client', import.meta.url) || 'webpack-hot-middleware/client' app.unshift( // https://github.com/glenjamin/webpack-hot-middleware#config - `webpack-hot-middleware/client?${hotMiddlewareClientOptionsStr}` + `${pathToFileURL(hotMiddlewarePath)}?${hotMiddlewareClientOptionsStr}` ) ctx.config.plugins = ctx.config.plugins || [] diff --git a/packages/webpack/src/presets/assets.ts b/packages/webpack/src/presets/assets.ts index 9195c05031..f55a3736fc 100644 --- a/packages/webpack/src/presets/assets.ts +++ b/packages/webpack/src/presets/assets.ts @@ -1,12 +1,13 @@ +import { tryResolveModule } from '@nuxt/kit' import type { WebpackConfigContext } from '../utils/config' import { fileName } from '../utils/config' -export function assets (ctx: WebpackConfigContext) { +export async function assets (ctx: WebpackConfigContext) { ctx.config.module!.rules!.push( { test: /\.(png|jpe?g|gif|svg|webp)$/i, use: [{ - loader: 'url-loader', + loader: await tryResolveModule('url-loader', import.meta.url) ?? 'url-loader', options: { ...ctx.userConfig.loaders.imgUrl, name: fileName(ctx, 'img') @@ -16,7 +17,7 @@ export function assets (ctx: WebpackConfigContext) { { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, use: [{ - loader: 'url-loader', + loader: await tryResolveModule('url-loader', import.meta.url) ?? 'url-loader', options: { ...ctx.userConfig.loaders.fontUrl, name: fileName(ctx, 'font') @@ -26,7 +27,7 @@ export function assets (ctx: WebpackConfigContext) { { test: /\.(webm|mp4|ogv)$/i, use: [{ - loader: 'file-loader', + loader: await tryResolveModule('file-loader', import.meta.url) ?? 'file-loader', options: { ...ctx.userConfig.loaders.file, name: fileName(ctx, 'video') diff --git a/packages/webpack/src/presets/base.ts b/packages/webpack/src/presets/base.ts index ffcfb17930..d4839f4e1f 100644 --- a/packages/webpack/src/presets/base.ts +++ b/packages/webpack/src/presets/base.ts @@ -133,6 +133,8 @@ function baseResolve (ctx: WebpackConfigContext) { // TODO: this might be refactored as default modulesDir? const webpackModulesDir = ['node_modules'].concat(ctx.options.modulesDir) + // console.log({webpackModulesDir}) + ctx.config.resolve = { extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.vue', '.jsx', '.tsx'], alias: ctx.alias, @@ -142,7 +144,7 @@ function baseResolve (ctx: WebpackConfigContext) { } ctx.config.resolveLoader = { - modules: webpackModulesDir, + // modules: webpackModulesDir, ...ctx.config.resolveLoader } } diff --git a/packages/webpack/src/presets/esbuild.ts b/packages/webpack/src/presets/esbuild.ts index 6c3155fc41..d821dac7ef 100644 --- a/packages/webpack/src/presets/esbuild.ts +++ b/packages/webpack/src/presets/esbuild.ts @@ -1,7 +1,8 @@ import { EsbuildPlugin } from 'esbuild-loader' +import { tryResolveModule } from '@nuxt/kit' import type { WebpackConfigContext } from '../utils/config' -export function esbuild (ctx: WebpackConfigContext) { +export async function esbuild (ctx: WebpackConfigContext) { // https://esbuild.github.io/getting-started/#bundling-for-the-browser // https://gs.statcounter.com/browser-version-market-share // https://nodejs.org/en/ @@ -13,7 +14,7 @@ export function esbuild (ctx: WebpackConfigContext) { ctx.config.module!.rules!.push( { test: /\.m?[jt]s$/i, - loader: 'esbuild-loader', + loader: await tryResolveModule('esbuild-loader', import.meta.url) ?? 'esbuild-loader', exclude: (file) => { // Not exclude files outside node_modules file = file.split('node_modules', 2)[1] @@ -32,7 +33,7 @@ export function esbuild (ctx: WebpackConfigContext) { }, { test: /\.m?[jt]sx$/, - loader: 'esbuild-loader', + loader: await tryResolveModule('esbuild-loader', import.meta.url) ?? 'esbuild-loader', options: { target, ...ctx.nuxt.options.webpack.loaders.esbuild, diff --git a/packages/webpack/src/presets/pug.ts b/packages/webpack/src/presets/pug.ts index c98a612297..fb9c51b394 100644 --- a/packages/webpack/src/presets/pug.ts +++ b/packages/webpack/src/presets/pug.ts @@ -1,13 +1,14 @@ +import { tryResolveModule } from '@nuxt/kit' import type { WebpackConfigContext } from '../utils/config' -export function pug (ctx: WebpackConfigContext) { +export async function pug (ctx: WebpackConfigContext) { ctx.config.module!.rules!.push({ test: /\.pug$/i, oneOf: [ { resourceQuery: /^\?vue/i, use: [{ - loader: 'pug-plain-loader', + loader: await tryResolveModule('pug-plain-loader', import.meta.url) ?? 'pug-plain-loader', options: ctx.userConfig.loaders.pugPlain }] }, @@ -15,7 +16,7 @@ export function pug (ctx: WebpackConfigContext) { use: [ 'raw-loader', { - loader: 'pug-plain-loader', + loader: await tryResolveModule('pug-plain-loader', import.meta.url) ?? 'pug-plain-loader', options: ctx.userConfig.loaders.pugPlain } ] diff --git a/packages/webpack/src/presets/style.ts b/packages/webpack/src/presets/style.ts index 41f700f3de..a305ae361c 100644 --- a/packages/webpack/src/presets/style.ts +++ b/packages/webpack/src/presets/style.ts @@ -1,5 +1,6 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin' import CssMinimizerPlugin from 'css-minimizer-webpack-plugin' +import { tryResolveModule } from '@nuxt/kit' import type { WebpackConfigContext } from '../utils/config' import { applyPresets, fileName } from '../utils/config' import { getPostcssConfig } from '../utils/postcss' @@ -31,32 +32,32 @@ function extractCSS (ctx: WebpackConfigContext) { } } -function loaders (ctx: WebpackConfigContext) { +async function loaders (ctx: WebpackConfigContext) { // 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 - 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 - const lessLoader = { loader: 'less-loader', options: ctx.userConfig.loaders.less } - ctx.config.module!.rules!.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx)) + const lessLoader = { loader: await tryResolveModule('less-loader', import.meta.url) ?? 'less-loader', options: ctx.userConfig.loaders.less } + ctx.config.module!.rules!.push(await createdStyleRule('less', /\.less$/i, lessLoader, ctx)) // Sass (TODO: optional dependency) - const sassLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.sass } - ctx.config.module!.rules!.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx)) + const sassLoader = { loader: await tryResolveModule('sass-loader', import.meta.url) ?? 'sass-loader', options: ctx.userConfig.loaders.sass } + ctx.config.module!.rules!.push(await createdStyleRule('sass', /\.sass$/i, sassLoader, ctx)) - const scssLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.scss } - ctx.config.module!.rules!.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx)) + const scssLoader = { loader: await tryResolveModule('sass-loader', import.meta.url) ?? 'sass-loader', options: ctx.userConfig.loaders.scss } + ctx.config.module!.rules!.push(await createdStyleRule('scss', /\.scss$/i, scssLoader, ctx)) // Stylus - const stylusLoader = { loader: 'stylus-loader', options: ctx.userConfig.loaders.stylus } - ctx.config.module!.rules!.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx)) + const stylusLoader = { loader: await tryResolveModule('stylus-loader', import.meta.url) ?? 'stylus-loader', options: ctx.userConfig.loaders.stylus } + 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 = [ - createPostcssLoadersRule(ctx), + await createPostcssLoadersRule(ctx), processorLoader ].filter(Boolean) @@ -64,8 +65,8 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx ctx.userConfig.loaders.cssModules.importLoaders = styleLoaders.length - const cssLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.css) - const cssModuleLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.cssModules) + const cssLoaders = await createCssLoadersRule(ctx, ctx.userConfig.loaders.css) + const cssModuleLoaders = await createCssLoadersRule(ctx, ctx.userConfig.loaders.cssModules) return { test, @@ -83,8 +84,8 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx } } -function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) { - const cssLoader = { loader: 'css-loader', options: cssLoaderOptions } +async function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) { + const cssLoader = { loader: await tryResolveModule('css-loader', import.meta.url) ?? 'css-loader', options: cssLoaderOptions } if (ctx.userConfig.extractCSS) { if (ctx.isServer) { @@ -106,14 +107,14 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) return [ // https://github.com/vuejs/vue-style-loader/issues/56 // { - // loader: 'vue-style-loader', + // loader: await tryResolveModule('vue-style-loader', import.meta.url) ?? 'vue-style-loader', // options: options.webpack.loaders.vueStyle // }, cssLoader ] } -function createPostcssLoadersRule (ctx: WebpackConfigContext) { +async function createPostcssLoadersRule (ctx: WebpackConfigContext) { if (!ctx.options.postcss) { return } const config = getPostcssConfig(ctx.nuxt) @@ -123,7 +124,7 @@ function createPostcssLoadersRule (ctx: WebpackConfigContext) { } return { - loader: 'postcss-loader', + loader: await tryResolveModule('postcss-loader', import.meta.url) ?? 'postcss-loader', options: config } } diff --git a/packages/webpack/src/presets/vue.ts b/packages/webpack/src/presets/vue.ts index badc026655..eb21736bf9 100644 --- a/packages/webpack/src/presets/vue.ts +++ b/packages/webpack/src/presets/vue.ts @@ -1,17 +1,18 @@ import { resolve } from 'pathe' import VueLoaderPlugin from 'vue-loader/dist/pluginWebpack5.js' import webpack from 'webpack' +import { tryResolveModule } from '@nuxt/kit' import VueSSRClientPlugin from '../plugins/vue/client' import VueSSRServerPlugin from '../plugins/vue/server' import type { WebpackConfigContext } from '../utils/config' -export function vue (ctx: WebpackConfigContext) { +export async function vue (ctx: WebpackConfigContext) { // @ts-expect-error de-default vue-loader ctx.config.plugins!.push(new (VueLoaderPlugin.default || VueLoaderPlugin)()) ctx.config.module!.rules!.push({ test: /\.vue$/i, - loader: 'vue-loader', + loader: await tryResolveModule('vue-loader', import.meta.url) ?? 'vue-loader', options: { reactivityTransform: ctx.nuxt.options.experimental.reactivityTransform, ...ctx.userConfig.loaders.vue diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index f63a5e15a7..f92c57667c 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -130,7 +130,7 @@ export default defineNuxtConfig({ // in order to test bigint serialisation we need to set target to a more modern one for (const config of configs) { const esbuildRules = config.module!.rules!.filter( - rule => typeof rule === 'object' && rule && 'loader' in rule && rule.loader === 'esbuild-loader' + rule => typeof rule === 'object' && rule && 'loader' in rule && rule.loader?.includes('esbuild-loader') ) for (const rule of esbuildRules) { if (typeof rule === 'object' && typeof rule.options === 'object') {