diff --git a/docs/1.getting-started/12.upgrade.md b/docs/1.getting-started/12.upgrade.md index 0aa50fd46b..c87c95ec77 100644 --- a/docs/1.getting-started/12.upgrade.md +++ b/docs/1.getting-started/12.upgrade.md @@ -517,10 +517,7 @@ These options have been set to their current values for some time and we do not We have now removed the following utils exported from `@nuxt/kit`: -* `resolveModule` * `requireModule` -* `importModule` -* `tryImportModule` * `tryRequireModule` They were previously marked as deprecated and relied on CJS resolutions. diff --git a/packages/kit/src/index.ts b/packages/kit/src/index.ts index d035408183..4261e47a0d 100644 --- a/packages/kit/src/index.ts +++ b/packages/kit/src/index.ts @@ -32,4 +32,5 @@ export { addTemplate, addTypeTemplate, normalizeTemplate, updateTemplates, write export { logger, useLogger } from './logger' // Internal Utils -export { tryResolveModule } from './internal/esm' +export { resolveModule, tryResolveModule, importModule, tryImportModule } from './internal/esm' +export type { ImportModuleOptions, ResolveModuleOptions } from './internal/esm' diff --git a/packages/kit/src/internal/esm.ts b/packages/kit/src/internal/esm.ts index 54e4524a73..4501d77cea 100644 --- a/packages/kit/src/internal/esm.ts +++ b/packages/kit/src/internal/esm.ts @@ -1,6 +1,10 @@ import { pathToFileURL } from 'node:url' import { interopDefault, resolvePath } from 'mlly' +export interface ResolveModuleOptions { + paths?: string | string[] +} + /** * Resolve a module from a given root path using an algorithm patterned on * the upcoming `import.meta.resolve`. It returns a file URL @@ -15,14 +19,23 @@ export async function tryResolveModule (id: string, url: string | string[] = imp } } -export async function importModule (id: string, url: string | string[] = import.meta.url) { - const resolvedPath = await resolvePath(id, { url }) - return import(pathToFileURL(resolvedPath).href).then(interopDefault) +export async function resolveModule (id: string, options?: ResolveModuleOptions) { + return await resolvePath(id, { url: options?.paths ?? [import.meta.url] }) } -export function tryImportModule (id: string, url = import.meta.url) { +export interface ImportModuleOptions extends ResolveModuleOptions { + /** Automatically de-default the result of requiring the module. */ + interopDefault?: boolean +} + +export async function importModule (id: string, opts?: ImportModuleOptions) { + const resolvedPath = await resolveModule(id, opts) + return import(pathToFileURL(resolvedPath).href).then(r => opts?.interopDefault !== false ? interopDefault(r) : r) as Promise +} + +export function tryImportModule (id: string, opts?: ImportModuleOptions) { try { - return importModule(id, url).catch(() => undefined) + return importModule(id, opts).catch(() => undefined) } catch { // intentionally empty as this is a `try-` function } diff --git a/packages/kit/src/loader/nuxt.ts b/packages/kit/src/loader/nuxt.ts index ea43b6bcba..0c4727ffab 100644 --- a/packages/kit/src/loader/nuxt.ts +++ b/packages/kit/src/loader/nuxt.ts @@ -31,7 +31,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { const rootDir = pathToFileURL(opts.cwd!).href - const { loadNuxt } = await importModule((pkg as any)._name || pkg.name, rootDir) + const { loadNuxt } = await importModule((pkg as any)._name || pkg.name, { paths: rootDir }) const nuxt = await loadNuxt(opts) return nuxt } @@ -39,6 +39,6 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { export async function buildNuxt (nuxt: Nuxt): Promise { const rootDir = pathToFileURL(nuxt.options.rootDir).href - const { build } = await tryImportModule('nuxt-nightly', rootDir) || await importModule('nuxt', rootDir) + const { build } = await tryImportModule('nuxt-nightly', { paths: rootDir }) || await importModule('nuxt', { paths: rootDir }) return build(nuxt) } diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index 201cfe2b24..92bd04270d 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -1,9 +1,7 @@ -import { pathToFileURL } from 'node:url' import type { EventType } from '@parcel/watcher' import type { FSWatcher } from 'chokidar' import { watch as chokidarWatch } from 'chokidar' -import { isIgnored, logger, tryResolveModule, useNuxt } from '@nuxt/kit' -import { interopDefault } from 'mlly' +import { importModule, isIgnored, logger, tryResolveModule, useNuxt } from '@nuxt/kit' import { debounce } from 'perfect-debounce' import { normalize, relative, resolve } from 'pathe' import type { Nuxt, NuxtBuilder } from 'nuxt/schema' @@ -151,7 +149,7 @@ async function createParcelWatcher () { return false } - const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher') + const { subscribe } = await importModule(watcherPath) for (const layer of nuxt.options._layers) { if (!layer.config.srcDir) { continue } const watcher = subscribe(layer.config.srcDir, (err, events) => { @@ -201,5 +199,5 @@ async function loadBuilder (nuxt: Nuxt, builder: string): Promise { if (!builderPath) { throw new Error(`Loading \`${builder}\` builder failed. You can read more about the nuxt \`builder\` option at: \`https://nuxt.com/docs/api/nuxt-config#builder\``) } - return import(pathToFileURL(builderPath).href) + return importModule(builderPath) } diff --git a/packages/nuxt/src/core/schema.ts b/packages/nuxt/src/core/schema.ts index 1813377c3a..f93030f9d0 100644 --- a/packages/nuxt/src/core/schema.ts +++ b/packages/nuxt/src/core/schema.ts @@ -1,12 +1,11 @@ import { existsSync } from 'node:fs' import { mkdir, writeFile } from 'node:fs/promises' -import { fileURLToPath, pathToFileURL } from 'node:url' +import { fileURLToPath } from 'node:url' import { resolve } from 'pathe' import { watch } from 'chokidar' -import { interopDefault } from 'mlly' import { defu } from 'defu' import { debounce } from 'perfect-debounce' -import { createResolver, defineNuxtModule, logger, tryResolveModule } from '@nuxt/kit' +import { createResolver, defineNuxtModule, importModule, logger, tryResolveModule } from '@nuxt/kit' import { generateTypes, resolveSchema as resolveUntypedSchema, @@ -60,7 +59,7 @@ export default defineNuxtModule({ if (nuxt.options.experimental.watcher === 'parcel') { const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir]) if (watcherPath) { - const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher') + const { subscribe } = await importModule(watcherPath) for (const layer of nuxt.options._layers) { const subscription = await subscribe(layer.config.rootDir, onChange, { ignore: ['!nuxt.schema.*'], diff --git a/packages/webpack/src/nitro/plugins/dynamic-require.ts b/packages/webpack/src/nitro/plugins/dynamic-require.ts index a8e3460e09..18f987d782 100644 --- a/packages/webpack/src/nitro/plugins/dynamic-require.ts +++ b/packages/webpack/src/nitro/plugins/dynamic-require.ts @@ -1,8 +1,8 @@ -import { pathToFileURL } from 'node:url' import { globby } from 'globby' import { genSafeVariableName } from 'knitwork' import { resolve } from 'pathe' import type { Plugin } from 'rollup' +import { importModule } from '@nuxt/kit' const PLUGIN_NAME = 'dynamic-require' const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.mjs` @@ -61,9 +61,8 @@ export function dynamicRequire ({ dir, ignore, inline }: Options): Plugin { let files = [] try { const wpManifest = resolve(dir, './server.manifest.json') - files = await import(pathToFileURL(wpManifest).href).then(r => - Object.keys(r.files).filter(file => !ignore.includes(file)), - ) + files = await importModule<{ files: Record }>(wpManifest) + .then(r => Object.keys(r.files).filter(file => !ignore.includes(file))) } catch { files = await globby('**/*.{cjs,mjs,js}', { cwd: dir, @@ -89,9 +88,7 @@ export function dynamicRequire ({ dir, ignore, inline }: Options): Plugin { } async function getWebpackChunkMeta (src: string) { - const chunk = await import(pathToFileURL(src).href).then( - r => r.default || r || {}, - ) + const chunk = await importModule<{ id: string, ids: string[], modules: Record }>(src) || {} const { id, ids, modules } = chunk if (!id && !ids) { return null // Not a webpack chunk