From 3682b07faab2f41789371c3b40054f4ad80c226d Mon Sep 17 00:00:00 2001 From: Brijesh Bittu Date: Sat, 9 Nov 2024 18:01:12 +0530 Subject: [PATCH] [nextjs] Fix path resolution This reverts the previous "fix" and uses the newly available loaderContext from unplugin to do path resolution. Previous solution was "hacky" in a sense since at that time, Unplugin did not expose loader's context. So we had to do things manually which did not work reliably. Now that we have "loaderContext" data, it's straighforward to just call `loaderContext.resolve()` with the path and this works as expected. Tested on our docs and user submitted repro repository. --- packages/pigment-css-unplugin/src/index.ts | 82 +++++++++------------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/packages/pigment-css-unplugin/src/index.ts b/packages/pigment-css-unplugin/src/index.ts index 73100f72..1ae846a7 100644 --- a/packages/pigment-css-unplugin/src/index.ts +++ b/packages/pigment-css-unplugin/src/index.ts @@ -8,7 +8,7 @@ import { transform, createFileReporter, } from '@wyw-in-js/transform'; -import { asyncResolveFallback, slugify } from '@wyw-in-js/shared'; +import { slugify } from '@wyw-in-js/shared'; import { UnpluginFactoryOutput, WebpackPluginInstance, @@ -25,7 +25,6 @@ import { type PluginCustomOptions, } from '@pigment-css/react/utils'; import { styledEngineMockup } from '@pigment-css/react/internal'; - import { handleUrlReplacement, type AsyncResolver } from './utils'; type NextMeta = { @@ -158,19 +157,6 @@ export const plugin = createUnplugin((options) => { }; const projectPath = meta?.type === 'next' ? meta.projectPath : process.cwd(); - let webpackResolver: AsyncResolver; - - const asyncResolve: AsyncResolver = async (what, importer, stack) => { - const result = await asyncResolveOpt?.(what, importer, stack); - if (typeof result === 'string') { - return result; - } - if (webpackResolver) { - return webpackResolver(what, importer, stack); - } - return asyncResolveFallback(what, importer, stack); - }; - const withRtl = (selector: string, cssText: string) => { return basePreprocessor(selector, cssText, css); }; @@ -184,41 +170,41 @@ export const plugin = createUnplugin((options) => { transformInclude(id) { return isZeroRuntimeProcessableFile(id, finalTransformLibraries); }, - webpack(compiler) { - compiler.resolverFactory.hooks.resolver - .for('normal') - .tap(`${pluginName}Resolver`, (resolver) => { - webpackResolver = (what: string, importer: string, stack: string[]) => { - const context = path.isAbsolute(importer) - ? path.dirname(importer) - : path.join(projectPath, path.dirname(importer)); - return new Promise((resolve, reject) => { - resolver.resolve( - {}, - context, - what, - { - stack: new Set(stack), - }, - (err, result) => { - if (typeof result !== 'string') { - reject(new Error(`${process.env.PACKAGE_NAME}: Could not resolve ${what}`)); - } else if (result) { - resolve(result); - } else { - reject(err); - } - }, - ); - }); - }; - }); - }, async transform(code, url) { const [filePath] = url.split('?'); // Converts path separator as per platform, even on Windows, path segments have `/` instead of the usual `\`, // so this function replaces such path separators. const id = path.normalize(filePath); + // @ts-ignore + const nativeContext = this.getNativeBuildContext(); + if (nativeContext?.framework !== 'webpack') { + throw new Error('This plugin should only be used with Webpack/Next.js.'); + } + const asyncResolve = async ( + token: string, + importer: string, + stack: string[], + ): Promise => { + const njsResult = await asyncResolveOpt?.(token, importer, stack); + if (typeof njsResult === 'string') { + return njsResult; + } + const context = path.isAbsolute(importer) + ? path.dirname(importer) + : path.join(projectPath, path.dirname(importer)); + return new Promise((resolve, reject) => { + nativeContext.loaderContext!.resolve(context, token, (err, result) => { + if (err) { + reject(err); + } else if (result) { + nativeContext.loaderContext!.addDependency(result); + resolve(result); + } else { + reject(new Error(`${process.env.PACKAGE_NAME}: Cannot resolve ${token}`)); + } + }); + }); + }; const transformServices = { options: { filename: id, @@ -344,13 +330,13 @@ export const plugin = createUnplugin((options) => { }; } - const rootPath = process.cwd(); - const cssFilename = path .normalize(`${id.replace(/\.[jt]sx?$/, '')}-${slug}.pigment.css`) .replace(/\\/g, path.posix.sep); - const cssRelativePath = path.relative(rootPath, cssFilename).replace(/\\/g, path.posix.sep); + const cssRelativePath = path + .relative(projectPath, cssFilename) + .replace(/\\/g, path.posix.sep); // Starting with null character so that it calls the resolver method (resolveId in line:430) // Otherwise, webpack tries to resolve the path directly const cssId = `\0${cssRelativePath}`;