feat(kit): reimplement cjs utils using mlly (#28012)

This commit is contained in:
Daniel Roe 2024-07-03 23:02:05 +01:00 committed by GitHub
parent e0d8ab3e69
commit ef35ff27df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 27 deletions

View File

@ -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`: We have now removed the following utils exported from `@nuxt/kit`:
* `resolveModule`
* `requireModule` * `requireModule`
* `importModule`
* `tryImportModule`
* `tryRequireModule` * `tryRequireModule`
They were previously marked as deprecated and relied on CJS resolutions. They were previously marked as deprecated and relied on CJS resolutions.

View File

@ -32,4 +32,5 @@ export { addTemplate, addTypeTemplate, normalizeTemplate, updateTemplates, write
export { logger, useLogger } from './logger' export { logger, useLogger } from './logger'
// Internal Utils // Internal Utils
export { tryResolveModule } from './internal/esm' export { resolveModule, tryResolveModule, importModule, tryImportModule } from './internal/esm'
export type { ImportModuleOptions, ResolveModuleOptions } from './internal/esm'

View File

@ -1,6 +1,10 @@
import { pathToFileURL } from 'node:url' import { pathToFileURL } from 'node:url'
import { interopDefault, resolvePath } from 'mlly' import { interopDefault, resolvePath } from 'mlly'
export interface ResolveModuleOptions {
paths?: string | string[]
}
/** /**
* Resolve a module from a given root path using an algorithm patterned on * Resolve a module from a given root path using an algorithm patterned on
* the upcoming `import.meta.resolve`. It returns a file URL * 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) { export async function resolveModule (id: string, options?: ResolveModuleOptions) {
const resolvedPath = await resolvePath(id, { url }) return await resolvePath(id, { url: options?.paths ?? [import.meta.url] })
return import(pathToFileURL(resolvedPath).href).then(interopDefault)
} }
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<T = unknown> (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<T>
}
export function tryImportModule<T = unknown> (id: string, opts?: ImportModuleOptions) {
try { try {
return importModule(id, url).catch(() => undefined) return importModule<T>(id, opts).catch(() => undefined)
} catch { } catch {
// intentionally empty as this is a `try-` function // intentionally empty as this is a `try-` function
} }

View File

@ -31,7 +31,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
const rootDir = pathToFileURL(opts.cwd!).href const rootDir = pathToFileURL(opts.cwd!).href
const { loadNuxt } = await importModule((pkg as any)._name || pkg.name, rootDir) const { loadNuxt } = await importModule<typeof import('nuxt')>((pkg as any)._name || pkg.name, { paths: rootDir })
const nuxt = await loadNuxt(opts) const nuxt = await loadNuxt(opts)
return nuxt return nuxt
} }
@ -39,6 +39,6 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
export async function buildNuxt (nuxt: Nuxt): Promise<any> { export async function buildNuxt (nuxt: Nuxt): Promise<any> {
const rootDir = pathToFileURL(nuxt.options.rootDir).href const rootDir = pathToFileURL(nuxt.options.rootDir).href
const { build } = await tryImportModule('nuxt-nightly', rootDir) || await importModule('nuxt', rootDir) const { build } = await tryImportModule<typeof import('nuxt')>('nuxt-nightly', { paths: rootDir }) || await importModule<typeof import('nuxt')>('nuxt', { paths: rootDir })
return build(nuxt) return build(nuxt)
} }

View File

@ -1,9 +1,7 @@
import { pathToFileURL } from 'node:url'
import type { EventType } from '@parcel/watcher' import type { EventType } from '@parcel/watcher'
import type { FSWatcher } from 'chokidar' import type { FSWatcher } from 'chokidar'
import { watch as chokidarWatch } from 'chokidar' import { watch as chokidarWatch } from 'chokidar'
import { isIgnored, logger, tryResolveModule, useNuxt } from '@nuxt/kit' import { importModule, isIgnored, logger, tryResolveModule, useNuxt } from '@nuxt/kit'
import { interopDefault } from 'mlly'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { normalize, relative, resolve } from 'pathe' import { normalize, relative, resolve } from 'pathe'
import type { Nuxt, NuxtBuilder } from 'nuxt/schema' import type { Nuxt, NuxtBuilder } from 'nuxt/schema'
@ -151,7 +149,7 @@ async function createParcelWatcher () {
return false return false
} }
const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher') const { subscribe } = await importModule<typeof import('@parcel/watcher')>(watcherPath)
for (const layer of nuxt.options._layers) { for (const layer of nuxt.options._layers) {
if (!layer.config.srcDir) { continue } if (!layer.config.srcDir) { continue }
const watcher = subscribe(layer.config.srcDir, (err, events) => { const watcher = subscribe(layer.config.srcDir, (err, events) => {
@ -201,5 +199,5 @@ async function loadBuilder (nuxt: Nuxt, builder: string): Promise<NuxtBuilder> {
if (!builderPath) { 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\``) 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)
} }

View File

@ -1,12 +1,11 @@
import { existsSync } from 'node:fs' import { existsSync } from 'node:fs'
import { mkdir, writeFile } from 'node:fs/promises' import { mkdir, writeFile } from 'node:fs/promises'
import { fileURLToPath, pathToFileURL } from 'node:url' import { fileURLToPath } from 'node:url'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import { watch } from 'chokidar' import { watch } from 'chokidar'
import { interopDefault } from 'mlly'
import { defu } from 'defu' import { defu } from 'defu'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { createResolver, defineNuxtModule, logger, tryResolveModule } from '@nuxt/kit' import { createResolver, defineNuxtModule, importModule, logger, tryResolveModule } from '@nuxt/kit'
import { import {
generateTypes, generateTypes,
resolveSchema as resolveUntypedSchema, resolveSchema as resolveUntypedSchema,
@ -60,7 +59,7 @@ export default defineNuxtModule({
if (nuxt.options.experimental.watcher === 'parcel') { if (nuxt.options.experimental.watcher === 'parcel') {
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir]) const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir])
if (watcherPath) { if (watcherPath) {
const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher') const { subscribe } = await importModule<typeof import('@parcel/watcher')>(watcherPath)
for (const layer of nuxt.options._layers) { for (const layer of nuxt.options._layers) {
const subscription = await subscribe(layer.config.rootDir, onChange, { const subscription = await subscribe(layer.config.rootDir, onChange, {
ignore: ['!nuxt.schema.*'], ignore: ['!nuxt.schema.*'],

View File

@ -1,8 +1,8 @@
import { pathToFileURL } from 'node:url'
import { globby } from 'globby' import { globby } from 'globby'
import { genSafeVariableName } from 'knitwork' import { genSafeVariableName } from 'knitwork'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import type { Plugin } from 'rollup' import type { Plugin } from 'rollup'
import { importModule } from '@nuxt/kit'
const PLUGIN_NAME = 'dynamic-require' const PLUGIN_NAME = 'dynamic-require'
const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.mjs` const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.mjs`
@ -61,9 +61,8 @@ export function dynamicRequire ({ dir, ignore, inline }: Options): Plugin {
let files = [] let files = []
try { try {
const wpManifest = resolve(dir, './server.manifest.json') const wpManifest = resolve(dir, './server.manifest.json')
files = await import(pathToFileURL(wpManifest).href).then(r => files = await importModule<{ files: Record<string, unknown> }>(wpManifest)
Object.keys(r.files).filter(file => !ignore.includes(file)), .then(r => Object.keys(r.files).filter(file => !ignore.includes(file)))
)
} catch { } catch {
files = await globby('**/*.{cjs,mjs,js}', { files = await globby('**/*.{cjs,mjs,js}', {
cwd: dir, cwd: dir,
@ -89,9 +88,7 @@ export function dynamicRequire ({ dir, ignore, inline }: Options): Plugin {
} }
async function getWebpackChunkMeta (src: string) { async function getWebpackChunkMeta (src: string) {
const chunk = await import(pathToFileURL(src).href).then( const chunk = await importModule<{ id: string, ids: string[], modules: Record<string, unknown> }>(src) || {}
r => r.default || r || {},
)
const { id, ids, modules } = chunk const { id, ids, modules } = chunk
if (!id && !ids) { if (!id && !ids) {
return null // Not a webpack chunk return null // Not a webpack chunk