From 3ac5d734f90373ccb05a4043156953f3010e3be9 Mon Sep 17 00:00:00 2001 From: Naman Goel Date: Sun, 12 Jan 2025 19:27:12 -0800 Subject: [PATCH] fix: move alias rewriting to babel plugin --- packages/babel-plugin/src/index.js | 44 ++++++ .../babel-plugin/src/utils/state-manager.js | 21 ++- packages/cli/src/plugins.js | 142 ------------------ packages/cli/src/transform.js | 11 +- 4 files changed, 66 insertions(+), 152 deletions(-) diff --git a/packages/babel-plugin/src/index.js b/packages/babel-plugin/src/index.js index 106ffc1a8..5361066b6 100644 --- a/packages/babel-plugin/src/index.js +++ b/packages/babel-plugin/src/index.js @@ -12,6 +12,12 @@ import type { NodePath } from '@babel/traverse'; import type { PluginObj } from '@babel/core'; import type { StyleXOptions } from './utils/state-manager'; import StateManager from './utils/state-manager'; +import { + EXTENSIONS, + filePathResolver, + matchesFileSuffix, + getRelativePath, +} from './utils/state-manager'; import { readImportDeclarations, readRequires } from './visitors/imports'; import transformStyleXCreate from './visitors/stylex-create'; import transformStyleXDefineVars from './visitors/stylex-define-vars'; @@ -74,6 +80,44 @@ function styleXTransform(): PluginObj<> { // variables entirely if they're not needed. exit: (path: NodePath) => { path.traverse({ + ImportDeclaration(path: NodePath) { + const filename = state.filename; + if (filename == null || !state.options.rewriteAliases) { + return; + } + + const source = path.node.source.value; + + const aliases = state.options.aliases; + + const themeFileExtension = '.stylex'; + if (!matchesFileSuffix(themeFileExtension)(source)) { + return; + } + const resolvedFilePath = filePathResolver( + source, + filename, + aliases, + ); + + if (resolvedFilePath == null) { + return; + } + + let relativeFilePath = getRelativePath( + filename, + resolvedFilePath, + ); + + const extension = EXTENSIONS.find((ext) => + relativeFilePath.endsWith(ext), + ); + if (extension != null) { + relativeFilePath = relativeFilePath.slice(0, -extension.length); + } + + path.node.source.value = relativeFilePath; + }, Identifier(path: NodePath) { // Look for variables bound to `stylex.create` calls that are used // outside of `stylex(...)` calls diff --git a/packages/babel-plugin/src/utils/state-manager.js b/packages/babel-plugin/src/utils/state-manager.js index d9707acb5..8e42bde01 100644 --- a/packages/babel-plugin/src/utils/state-manager.js +++ b/packages/babel-plugin/src/utils/state-manager.js @@ -78,6 +78,7 @@ export type StyleXOptions = $ReadOnly<{ genConditionalClasses: boolean, unstable_moduleResolution?: ?ModuleResolution, aliases?: ?$ReadOnly<{ [string]: string | $ReadOnlyArray }>, + rewriteAliases?: boolean, ... }>; @@ -85,6 +86,7 @@ type StyleXStateOptions = $ReadOnly<{ ...StyleXOptions, runtimeInjection: ?string | $ReadOnly<{ from: string, as: ?string }>, aliases?: ?$ReadOnly<{ [string]: $ReadOnlyArray }>, + rewriteAliases: boolean, ... }>; @@ -289,6 +291,10 @@ export default class StateManager { styleResolution, unstable_moduleResolution, treeshakeCompensation, + rewriteAliases: + typeof options.rewriteAliases === 'boolean' + ? options.rewriteAliases + : false, }; return opts; } @@ -702,7 +708,7 @@ export const filePathResolver = ( return null; }; -const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; +export const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; const addFileExtension = ( importedFilePath: string, @@ -748,3 +754,16 @@ const getProgramStatement = (path: NodePath<>): NodePath<> => { } return programPath; }; + +export function getRelativePath(from: string, to: string): string { + const relativePath = path.relative(path.parse(from).dir, to); + return formatRelativePath(toPosixPath(relativePath)); +} + +function toPosixPath(filePath: string): string { + return filePath.split(path.sep).join(path.posix.sep); +} + +function formatRelativePath(filePath: string) { + return filePath.startsWith('.') ? filePath : './' + filePath; +} diff --git a/packages/cli/src/plugins.js b/packages/cli/src/plugins.js index 52827fe8b..db9e2fdbd 100644 --- a/packages/cli/src/plugins.js +++ b/packages/cli/src/plugins.js @@ -12,8 +12,6 @@ import type { NodePath } from '@babel/traverse'; import { getRelativePath } from './files'; import { findModuleDir } from './modules'; import * as t from '@babel/types'; -import { moduleResolve } from '@dual-bundle/import-meta-resolve'; -import url from 'url'; import * as nodePath from 'path'; @@ -121,143 +119,3 @@ export const createModuleImportModifierPlugin = ( }, }; }; - -export const createAliasRewritePlugin = ( - sourceFilePath: string, - aliasConfig: $ReadOnly<{ [string]: string | $ReadOnlyArray }>, -): ImportModifierPlugin => { - return { - visitor: { - Program: { - exit(path: NodePath) { - path.traverse({ - ImportDeclaration: { - enter(path: NodePath) { - const source = path.node.source.value; - - const aliases = - aliasConfig == null - ? aliasConfig - : Object.fromEntries( - Object.entries(aliasConfig).map(([key, value]) => { - if (typeof value === 'string') { - return [key, [value]]; - } - return [key, value]; - }), - ); - - const themeFileExtension = '.stylex'; - if (!matchesFileSuffix(themeFileExtension)(source)) { - return; - } - const resolvedFilePath = filePathResolver( - source, - sourceFilePath, - aliases, - ); - - if (resolvedFilePath == null) { - return; - } - - let relativeFilePath = getRelativePath( - sourceFilePath, - resolvedFilePath, - ); - - const extension = EXTENSIONS.find((ext) => - relativeFilePath.endsWith(ext), - ); - if (extension != null) { - relativeFilePath = relativeFilePath.slice( - 0, - -extension.length, - ); - } - - path.node.source.value = relativeFilePath; - }, - }, - }); - }, - }, - }, - }; -}; - -const matchesFileSuffix = (allowedSuffix: string) => (filename: string) => - filename.endsWith(`${allowedSuffix}.js`) || - filename.endsWith(`${allowedSuffix}.ts`) || - filename.endsWith(`${allowedSuffix}.tsx`) || - filename.endsWith(`${allowedSuffix}.jsx`) || - filename.endsWith(`${allowedSuffix}.mjs`) || - filename.endsWith(`${allowedSuffix}.cjs`) || - filename.endsWith(allowedSuffix); - -const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; -const filePathResolver = ( - relativeFilePath: string, - sourceFilePath: string, - aliases: $ReadOnly<{ [string]: $ReadOnlyArray }>, -): ?string => { - // Try importing without adding any extension - // and then every supported extension - for (const ext of ['', ...EXTENSIONS]) { - const importPathStr = relativeFilePath + ext; - - // Try to resolve relative paths as is - if (importPathStr.startsWith('.')) { - try { - return moduleResolve(importPathStr, url.pathToFileURL(sourceFilePath)) - .pathname; - } catch { - continue; - } - } - - // Otherwise, try to resolve the path with aliases - const allAliases = possibleAliasedPaths(importPathStr, aliases); - for (const possiblePath of allAliases) { - try { - return moduleResolve(possiblePath, url.pathToFileURL(sourceFilePath)) - .pathname; - } catch { - continue; - } - } - } - // Failed to resolve the file path - return null; -}; - -function possibleAliasedPaths( - importPath: string, - aliases: $ReadOnly<{ [string]: $ReadOnlyArray }>, -): $ReadOnlyArray { - const result = [importPath]; - if (aliases == null || Object.keys(aliases).length === 0) { - return result; - } - - for (const [alias, value] of Object.entries(aliases)) { - if (alias.includes('*')) { - const [before, after] = alias.split('*'); - if (importPath.startsWith(before) && importPath.endsWith(after)) { - const replacementString = importPath.slice( - before.length, - after.length > 0 ? -after.length : undefined, - ); - value.forEach((v) => { - result.push(v.split('*').join(replacementString)); - }); - } - } else if (alias === importPath) { - value.forEach((v) => { - result.push(v); - }); - } - } - - return result; -} diff --git a/packages/cli/src/transform.js b/packages/cli/src/transform.js index a54348c4d..94066270d 100644 --- a/packages/cli/src/transform.js +++ b/packages/cli/src/transform.js @@ -31,7 +31,6 @@ import { getDefaultCachePath, } from './cache'; import { - createAliasRewritePlugin, createImportPlugin, createModuleImportModifierPlugin, } from './plugins'; @@ -156,8 +155,6 @@ export async function transformFile( : path.join(config.output, config.styleXBundleName), ); - const aliases = config.styleXConfig?.aliases; - const result = await babel.transformFileAsync(inputFilePath, { babelrc: false, presets: config.babelPresets, @@ -173,15 +170,11 @@ export async function transformFile( rootDir: path.parse(config.output).dir, }, ...(config.styleXConfig as $FlowFixMe), + rewriteAliases: true, }, ], createImportPlugin(relativeImport), - ...[ - aliases != null - ? createAliasRewritePlugin(inputFilePath, aliases) - : null, - ...(config.babelPluginsPost ?? []), - ].filter(Boolean), + ...(config.babelPluginsPost ?? []), ], }); if (result == null) {