fix(webpack): resolve loaders to absolute paths

This commit is contained in:
Daniel Roe 2023-07-25 12:50:20 +01:00
parent 98c195f83e
commit 1d847c7514
8 changed files with 46 additions and 37 deletions

View File

@ -1,8 +1,9 @@
import querystring from 'node:querystring' import querystring from 'node:querystring'
import { pathToFileURL } from 'node:url'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import webpack from 'webpack' import webpack from 'webpack'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import { logger } from '@nuxt/kit' import { logger, tryResolveModule } from '@nuxt/kit'
import { joinURL } from 'ufo' import { joinURL } from 'ufo'
import ForkTSCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' 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) { if (!ctx.isDev) {
return return
} }
@ -65,9 +66,10 @@ function clientHMR (ctx: WebpackConfigContext) {
// Add HMR support // Add HMR support
const app = (ctx.config.entry as any).app as any 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( app.unshift(
// https://github.com/glenjamin/webpack-hot-middleware#config // https://github.com/glenjamin/webpack-hot-middleware#config
`webpack-hot-middleware/client?${hotMiddlewareClientOptionsStr}` `${pathToFileURL(hotMiddlewarePath)}?${hotMiddlewareClientOptionsStr}`
) )
ctx.config.plugins = ctx.config.plugins || [] ctx.config.plugins = ctx.config.plugins || []

View File

@ -1,12 +1,13 @@
import { tryResolveModule } from '@nuxt/kit'
import type { WebpackConfigContext } from '../utils/config' import type { WebpackConfigContext } from '../utils/config'
import { fileName } from '../utils/config' import { fileName } from '../utils/config'
export function assets (ctx: WebpackConfigContext) { export async function assets (ctx: WebpackConfigContext) {
ctx.config.module!.rules!.push( ctx.config.module!.rules!.push(
{ {
test: /\.(png|jpe?g|gif|svg|webp)$/i, test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [{ use: [{
loader: 'url-loader', loader: await tryResolveModule('url-loader', import.meta.url) ?? 'url-loader',
options: { options: {
...ctx.userConfig.loaders.imgUrl, ...ctx.userConfig.loaders.imgUrl,
name: fileName(ctx, 'img') name: fileName(ctx, 'img')
@ -16,7 +17,7 @@ export function assets (ctx: WebpackConfigContext) {
{ {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [{ use: [{
loader: 'url-loader', loader: await tryResolveModule('url-loader', import.meta.url) ?? 'url-loader',
options: { options: {
...ctx.userConfig.loaders.fontUrl, ...ctx.userConfig.loaders.fontUrl,
name: fileName(ctx, 'font') name: fileName(ctx, 'font')
@ -26,7 +27,7 @@ export function assets (ctx: WebpackConfigContext) {
{ {
test: /\.(webm|mp4|ogv)$/i, test: /\.(webm|mp4|ogv)$/i,
use: [{ use: [{
loader: 'file-loader', loader: await tryResolveModule('file-loader', import.meta.url) ?? 'file-loader',
options: { options: {
...ctx.userConfig.loaders.file, ...ctx.userConfig.loaders.file,
name: fileName(ctx, 'video') name: fileName(ctx, 'video')

View File

@ -133,6 +133,8 @@ function baseResolve (ctx: WebpackConfigContext) {
// TODO: this might be refactored as default modulesDir? // TODO: this might be refactored as default modulesDir?
const webpackModulesDir = ['node_modules'].concat(ctx.options.modulesDir) const webpackModulesDir = ['node_modules'].concat(ctx.options.modulesDir)
// console.log({webpackModulesDir})
ctx.config.resolve = { ctx.config.resolve = {
extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.vue', '.jsx', '.tsx'], extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.vue', '.jsx', '.tsx'],
alias: ctx.alias, alias: ctx.alias,
@ -142,7 +144,7 @@ function baseResolve (ctx: WebpackConfigContext) {
} }
ctx.config.resolveLoader = { ctx.config.resolveLoader = {
modules: webpackModulesDir, // modules: webpackModulesDir,
...ctx.config.resolveLoader ...ctx.config.resolveLoader
} }
} }

View File

@ -1,7 +1,8 @@
import { EsbuildPlugin } from 'esbuild-loader' import { EsbuildPlugin } from 'esbuild-loader'
import { tryResolveModule } from '@nuxt/kit'
import type { WebpackConfigContext } from '../utils/config' 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://esbuild.github.io/getting-started/#bundling-for-the-browser
// https://gs.statcounter.com/browser-version-market-share // https://gs.statcounter.com/browser-version-market-share
// https://nodejs.org/en/ // https://nodejs.org/en/
@ -13,7 +14,7 @@ export function esbuild (ctx: WebpackConfigContext) {
ctx.config.module!.rules!.push( ctx.config.module!.rules!.push(
{ {
test: /\.m?[jt]s$/i, test: /\.m?[jt]s$/i,
loader: 'esbuild-loader', loader: await tryResolveModule('esbuild-loader', import.meta.url) ?? 'esbuild-loader',
exclude: (file) => { exclude: (file) => {
// Not exclude files outside node_modules // Not exclude files outside node_modules
file = file.split('node_modules', 2)[1] file = file.split('node_modules', 2)[1]
@ -32,7 +33,7 @@ export function esbuild (ctx: WebpackConfigContext) {
}, },
{ {
test: /\.m?[jt]sx$/, test: /\.m?[jt]sx$/,
loader: 'esbuild-loader', loader: await tryResolveModule('esbuild-loader', import.meta.url) ?? 'esbuild-loader',
options: { options: {
target, target,
...ctx.nuxt.options.webpack.loaders.esbuild, ...ctx.nuxt.options.webpack.loaders.esbuild,

View File

@ -1,13 +1,14 @@
import { tryResolveModule } from '@nuxt/kit'
import type { WebpackConfigContext } from '../utils/config' import type { WebpackConfigContext } from '../utils/config'
export function pug (ctx: WebpackConfigContext) { export async function pug (ctx: WebpackConfigContext) {
ctx.config.module!.rules!.push({ ctx.config.module!.rules!.push({
test: /\.pug$/i, test: /\.pug$/i,
oneOf: [ oneOf: [
{ {
resourceQuery: /^\?vue/i, resourceQuery: /^\?vue/i,
use: [{ use: [{
loader: 'pug-plain-loader', loader: await tryResolveModule('pug-plain-loader', import.meta.url) ?? 'pug-plain-loader',
options: ctx.userConfig.loaders.pugPlain options: ctx.userConfig.loaders.pugPlain
}] }]
}, },
@ -15,7 +16,7 @@ export function pug (ctx: WebpackConfigContext) {
use: [ use: [
'raw-loader', 'raw-loader',
{ {
loader: 'pug-plain-loader', loader: await tryResolveModule('pug-plain-loader', import.meta.url) ?? 'pug-plain-loader',
options: ctx.userConfig.loaders.pugPlain options: ctx.userConfig.loaders.pugPlain
} }
] ]

View File

@ -1,5 +1,6 @@
import MiniCssExtractPlugin from 'mini-css-extract-plugin' import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin' import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import { tryResolveModule } from '@nuxt/kit'
import type { WebpackConfigContext } from '../utils/config' 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'
@ -31,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: await tryResolveModule('less-loader', import.meta.url) ?? '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: await tryResolveModule('sass-loader', import.meta.url) ?? '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: await tryResolveModule('sass-loader', import.meta.url) ?? '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: await tryResolveModule('stylus-loader', import.meta.url) ?? '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)
@ -64,8 +65,8 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx
ctx.userConfig.loaders.cssModules.importLoaders = ctx.userConfig.loaders.cssModules.importLoaders =
styleLoaders.length styleLoaders.length
const cssLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.css) const cssLoaders = await createCssLoadersRule(ctx, ctx.userConfig.loaders.css)
const cssModuleLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.cssModules) const cssModuleLoaders = await createCssLoadersRule(ctx, ctx.userConfig.loaders.cssModules)
return { return {
test, test,
@ -83,8 +84,8 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx
} }
} }
function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) { async function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) {
const cssLoader = { loader: 'css-loader', options: cssLoaderOptions } const cssLoader = { loader: await tryResolveModule('css-loader', import.meta.url) ?? 'css-loader', options: cssLoaderOptions }
if (ctx.userConfig.extractCSS) { if (ctx.userConfig.extractCSS) {
if (ctx.isServer) { if (ctx.isServer) {
@ -106,14 +107,14 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any)
return [ return [
// https://github.com/vuejs/vue-style-loader/issues/56 // 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 // options: options.webpack.loaders.vueStyle
// }, // },
cssLoader cssLoader
] ]
} }
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 = getPostcssConfig(ctx.nuxt)
@ -123,7 +124,7 @@ function createPostcssLoadersRule (ctx: WebpackConfigContext) {
} }
return { return {
loader: 'postcss-loader', loader: await tryResolveModule('postcss-loader', import.meta.url) ?? 'postcss-loader',
options: config options: config
} }
} }

View File

@ -1,17 +1,18 @@
import { resolve } from 'pathe' import { resolve } from 'pathe'
import VueLoaderPlugin from 'vue-loader/dist/pluginWebpack5.js' import VueLoaderPlugin from 'vue-loader/dist/pluginWebpack5.js'
import webpack from 'webpack' import webpack from 'webpack'
import { tryResolveModule } from '@nuxt/kit'
import VueSSRClientPlugin from '../plugins/vue/client' import VueSSRClientPlugin from '../plugins/vue/client'
import VueSSRServerPlugin from '../plugins/vue/server' import VueSSRServerPlugin from '../plugins/vue/server'
import type { WebpackConfigContext } from '../utils/config' import type { WebpackConfigContext } from '../utils/config'
export function vue (ctx: WebpackConfigContext) { export async function vue (ctx: WebpackConfigContext) {
// @ts-expect-error de-default vue-loader // @ts-expect-error de-default vue-loader
ctx.config.plugins!.push(new (VueLoaderPlugin.default || VueLoaderPlugin)()) ctx.config.plugins!.push(new (VueLoaderPlugin.default || VueLoaderPlugin)())
ctx.config.module!.rules!.push({ ctx.config.module!.rules!.push({
test: /\.vue$/i, test: /\.vue$/i,
loader: 'vue-loader', loader: await tryResolveModule('vue-loader', import.meta.url) ?? 'vue-loader',
options: { options: {
reactivityTransform: ctx.nuxt.options.experimental.reactivityTransform, reactivityTransform: ctx.nuxt.options.experimental.reactivityTransform,
...ctx.userConfig.loaders.vue ...ctx.userConfig.loaders.vue

View File

@ -130,7 +130,7 @@ export default defineNuxtConfig({
// in order to test bigint serialisation we need to set target to a more modern one // in order to test bigint serialisation we need to set target to a more modern one
for (const config of configs) { for (const config of configs) {
const esbuildRules = config.module!.rules!.filter( 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) { for (const rule of esbuildRules) {
if (typeof rule === 'object' && typeof rule.options === 'object') { if (typeof rule === 'object' && typeof rule.options === 'object') {