UNPKG

utquidem

Version:

The meta-framework suite designed from scratch for frontend-focused modern web development.

156 lines (145 loc) 4.29 kB
import fs from 'fs'; import path from 'path'; import { applyOptionsChain, findExists } from '@modern-js/utils'; import { NormalizedInputOptions, Plugin as RollupPlugin } from 'rollup'; import alias, { Alias } from '@rollup/plugin-alias'; import { createMatchPath, loadConfig, MatchPath } from 'tsconfig-paths'; import type { IAppContext, NormalizedConfig } from '@modern-js/core'; import { DEV_CLIENT_PATH, DEV_CLIENT_PATH_ALIAS, BARE_SPECIFIER_REGEX, DEFAULT_EXTENSIONS, } from '../constants'; // webpack alias to rollup alias entries export const normalizeAlias = ( config: NormalizedConfig, appContext: IAppContext, defaultDeps: string[], ) => { const result: Alias[] = [ { find: new RegExp(`^/?${appContext.internalDirAlias}/(.*)`), replacement: `${appContext.internalDirectory}/$1`, }, { find: new RegExp(`^/?${appContext.internalSrcAlias}/(.*)`), replacement: `${appContext.srcDirectory}/$1`, }, { find: new RegExp(`^\\/?${DEV_CLIENT_PATH_ALIAS}\\/(.*)`), replacement: `${DEV_CLIENT_PATH}/$1`, }, ]; // merge default config & user config const option = applyOptionsChain( { '@': './src', '@shared': appContext.sharedDirectory, }, config.source.alias as any, ); Object.keys(option).forEach(key => { const aliasPath = option[key]; const isAbsolute = path.isAbsolute(aliasPath); // should exclude modern-js/runtime api if (!defaultDeps.includes(key)) { result.push({ find: key, replacement: isAbsolute ? aliasPath : `/${path.resolve(process.cwd(), aliasPath)}`, }); } }); return result; }; export const aliasPlugin = ( config: NormalizedConfig, appContext: IAppContext, defaultDeps: string[], ): RollupPlugin => { const aliasOptions = normalizeAlias(config, appContext, defaultDeps); const plugin = alias({ entries: aliasOptions }); return { name: 'esm-alias', buildStart(options: NormalizedInputOptions) { return plugin.buildStart?.call(this, options); }, resolveId(id: string, importer?: string) { return plugin.resolveId?.call(this, id, importer, {} as any); }, }; }; /** Returns true when `path` is within `root` and not an installed dependency. */ const isLocalDescendant = (importer: string | undefined, root: string) => { if (importer) { return ( importer.startsWith(root) && !importer.slice(root.length).includes('/node_modules/') ); } else { return false; } }; export const tsAliasPlugin = ( config: NormalizedConfig, appContext: IAppContext, ): RollupPlugin => { const { appDirectory: root } = appContext; const tsConfig: any = loadConfig(root); let matchPath: MatchPath; const { resultType } = tsConfig; if (resultType === 'success' && tsConfig.paths) { matchPath = createMatchPath( tsConfig.absoluteBaseUrl, tsConfig.paths, tsConfig.mainFields || [ 'module', 'jsnext', 'jsnext:main', 'browser', 'main', ], tsConfig.addMatchAll, ); } const resolved = new Map<string, string>(); return { name: 'esm-ts-alias', resolveId(id, importer?: string) { if (!BARE_SPECIFIER_REGEX.test(id)) { return; } if (!matchPath) { return; } let result = resolved.get(id); if (!result && isLocalDescendant(importer, root)) { result = matchPath(id, undefined, undefined, DEFAULT_EXTENSIONS); if (result) { result = path.extname(result) ? result : (findExists( DEFAULT_EXTENSIONS.map(ext => { try { const isDir = fs.statSync(result as string).isDirectory(); if (isDir) { return path.resolve( root, `${result as string}/index${ext}`, ); } } catch (_err) { // ignore err } return path.resolve(root, `${result as string}${ext}`); }), ) as string); resolved.set(id, result); } } return result; }, }; };