Skip to content

Commit

Permalink
fix: missing dependency modules such as vue-i18n-routing and`@intli…
Browse files Browse the repository at this point in the history
…fy/vue-*` (#1692)
  • Loading branch information
kazupon authored Dec 4, 2022
1 parent 3e42988 commit 563d636
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 80 deletions.
103 changes: 65 additions & 38 deletions src/alias.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import createDebug from 'debug'
import { resolvePath } from '@nuxt/kit'
import { resolveVueI18nPkgPath, pkgModulesDir, getPackageManagerType } from './dirs'
import { resolve, parse as parsePath } from 'pathe'
import { resolveVueI18nPkgPath, pkgModulesDir } from './dirs'
import { resolve } from 'pathe'
import { VUE_I18N_PKG, VUE_I18N_BRIDGE_PKG, VUE_ROUTER_BRIDGE_PKG, VUE_I18N_ROUTING_PKG } from './constants'
import { tryResolve, getPackageManagerType } from './utils'

import type { Nuxt } from '@nuxt/schema'
import type { PackageManager } from './dirs'
import type { PackageManager } from './utils'

const debug = createDebug('@nuxtjs/i18n:alias')

Expand All @@ -24,17 +25,25 @@ export async function setupAlias(nuxt: Nuxt) {
debug('@intlify/shared alias', nuxt.options.alias['@intlify/shared'])

// resolve @intlify/vue-router-bridge
nuxt.options.alias[VUE_ROUTER_BRIDGE_PKG] = await resolveVueRouterBridgeAlias(pkgModulesDir, pkgMgr)
nuxt.options.alias[VUE_ROUTER_BRIDGE_PKG] = await resolveVueRouterBridgeAlias(
pkgModulesDir,
nuxt.options.rootDir,
pkgMgr
)
nuxt.options.build.transpile.push(VUE_ROUTER_BRIDGE_PKG)
debug('@intlify/vue-router-bridge alias', nuxt.options.alias[VUE_ROUTER_BRIDGE_PKG])

// resolve @intlify/vue-i18n-bridge
nuxt.options.alias[VUE_I18N_BRIDGE_PKG] = await resolveVueI18nBridgeAlias(pkgModulesDir, pkgMgr)
nuxt.options.alias[VUE_I18N_BRIDGE_PKG] = await resolveVueI18nBridgeAlias(pkgModulesDir, nuxt.options.rootDir, pkgMgr)
nuxt.options.build.transpile.push(VUE_I18N_BRIDGE_PKG)
debug('@intlify/vue-i18n-bridge alias', nuxt.options.alias[VUE_I18N_BRIDGE_PKG])

// resolve vue-i18n-routing
nuxt.options.alias[VUE_I18N_ROUTING_PKG] = await resolveVueI18nRoutingAlias(pkgModulesDir, pkgMgr)
nuxt.options.alias[VUE_I18N_ROUTING_PKG] = await resolveVueI18nRoutingAlias(
pkgModulesDir,
nuxt.options.rootDir,
pkgMgr
)
nuxt.options.build.transpile.push(VUE_I18N_ROUTING_PKG)
debug('vue-i18n-routing alias', nuxt.options.alias[VUE_I18N_ROUTING_PKG])
}
Expand All @@ -43,40 +52,58 @@ async function resolveVueI18nAlias(nuxt: Nuxt) {
return resolve(await resolveVueI18nPkgPath(), nuxt.options.dev ? 'dist/vue-i18n.mjs' : 'dist/vue-i18n.runtime.mjs')
}

async function resolveVueI18nBridgeAlias(pkgModuleDir: string, pkgMgr: PackageManager) {
if (pkgMgr === 'npm') {
debug(
'resolveVueI18nBridgeAlias on npm',
`${VUE_I18N_ROUTING_PKG}/node_modules/${VUE_I18N_BRIDGE_PKG}/lib/index.mjs`
)
return resolve(pkgModuleDir, `${VUE_I18N_ROUTING_PKG}/node_modules/${VUE_I18N_BRIDGE_PKG}/lib/index.mjs`)
} else {
const parsed = parsePath(await resolvePath(VUE_I18N_BRIDGE_PKG))
debug(`resolveVueI18nBridgeAlias on ${pkgMgr}`, parsed)
return `${parsed.dir}/${parsed.name}.mjs`
}
/**
* NOTE:
* The following packages may not be able to resolve the file paths of the target ES modules with `resolvePath`
* so they resolve them on their own (sometimes, these are resolved as `cjs`)
* - `vue-i18n-routing`
* - `@intlify/vue-i18n-bridge`
* - `@intlify/vue-router-bridge`
*/

async function resolveVueI18nBridgeAlias(pkgModulesDir: string, rootDir: string, pkgMgr: PackageManager) {
const modulePath = `${VUE_I18N_BRIDGE_PKG}/lib/index.mjs` as const
const targets = [
// 1st, try to resolve from `node_modules` (hoisted case)
resolve(rootDir, 'node_modules', modulePath),
// 2nd, try to resolve from `node_modules/vue-i18n-routing` (not hoisted case)
resolve(rootDir, 'node_modules', `${VUE_I18N_ROUTING_PKG}/node_modules`, modulePath),
// 3rd, try to resolve from `node_modules/@nuxtjs/i18n` (not hoisted case)
resolve(pkgModulesDir, modulePath),
// 4th, try to resolve from `node_modules/@nuxtjs/i18n/node_modules/vue-i18n-routing` (not hoisted case)
resolve(pkgModulesDir, `${VUE_I18N_ROUTING_PKG}/node_modules`, modulePath)
]
debug(`${VUE_I18N_BRIDGE_PKG} resolving from ...`, targets)

return tryResolve(VUE_I18N_BRIDGE_PKG, targets, pkgMgr)
}

async function resolveVueRouterBridgeAlias(pkgModuleDir: string, pkgMgr: PackageManager) {
if (pkgMgr === 'npm') {
debug('resolveVueRouterBridgeAlias on npm', `${VUE_ROUTER_BRIDGE_PKG}/lib/index.mjs`)
return resolve(pkgModuleDir, `${VUE_ROUTER_BRIDGE_PKG}/lib/index.mjs`)
} else {
const parsed = parsePath(await resolvePath(VUE_ROUTER_BRIDGE_PKG))
debug(`resolveVueRouterBridgeAlias on ${pkgMgr}`, parsed)
return `${parsed.dir}/${parsed.name}.mjs`
}
async function resolveVueRouterBridgeAlias(pkgModulesDir: string, rootDir: string, pkgMgr: PackageManager) {
const modulePath = `${VUE_ROUTER_BRIDGE_PKG}/lib/index.mjs` as const
const targets = [
// 1st, try to resolve from `node_modules` (hoisted case)
resolve(rootDir, 'node_modules', modulePath),
// 2nd, try to resolve from `node_modules/vue-i18n-routing` (not hoisted case)
resolve(rootDir, 'node_modules', `${VUE_I18N_ROUTING_PKG}/node_modules`, modulePath),
// 3rd, try to resolve from `node_modules/@nuxtjs/i18n` (not hoisted case)
resolve(pkgModulesDir, modulePath),
// 4th, try to resolve from `node_modules/@nuxtjs/i18n/node_modules/vue-i18n-routing` (not hoisted case)
resolve(pkgModulesDir, `${VUE_I18N_ROUTING_PKG}/node_modules`, modulePath)
]
debug(`${VUE_ROUTER_BRIDGE_PKG} resolving from ...`, targets)

return tryResolve(VUE_ROUTER_BRIDGE_PKG, targets, pkgMgr)
}

async function resolveVueI18nRoutingAlias(pkgModuleDir: string, pkgMgr: PackageManager) {
if (pkgMgr === 'npm') {
debug('resolveVueI18nRoutingAlias on npm', `${VUE_I18N_ROUTING_PKG}/dist/vue-i18n-routing.mjs`)
return resolve(pkgModuleDir, `${VUE_I18N_ROUTING_PKG}/dist/vue-i18n-routing.mjs`)
} else if (pkgMgr === 'pnpm' || pkgMgr === 'yarn') {
const parsed = parsePath(await resolvePath(VUE_I18N_ROUTING_PKG))
debug(`resolveVueI18nRoutingAlias on ${pkgMgr}`, parsed)
return `${parsed.dir}/dist/vue-i18n-routing.mjs`
} else {
return await resolvePath(VUE_I18N_ROUTING_PKG)
}
export async function resolveVueI18nRoutingAlias(pkgModulesDir: string, rootDir: string, pkgMgr: PackageManager) {
const modulePath = `${VUE_I18N_ROUTING_PKG}/dist/vue-i18n-routing.mjs` as const
const targets = [
// 1st, try to resolve from `node_modules` (hoisted case)
resolve(rootDir, 'node_modules', modulePath),
// 2nd, try to resolve from `node_modules/@nuxtjs/i18n` (not hoisted case)
resolve(pkgModulesDir, modulePath)
]
debug(`${VUE_I18N_ROUTING_PKG} resolving from ...`, targets)

return tryResolve(VUE_I18N_ROUTING_PKG, targets, pkgMgr)
}
53 changes: 14 additions & 39 deletions src/dirs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import createDebug from 'debug'
import { fileURLToPath } from 'node:url'
import { dirname, resolve, parse as parsePath } from 'pathe'
import { resolvePath } from '@nuxt/kit'
import { resolveLockfile } from 'pkg-types'
import { VUE_I18N_ROUTING_PKG } from './constants'
import { getPackageManagerType, tryResolve } from './utils'

const debug = createDebug('@nuxtjs/i18n:dirs')

Expand All @@ -12,54 +12,29 @@ export const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
const pkgDir = resolve(distDir, '..')
export const pkgModulesDir = resolve(pkgDir, './node_modules')

const PackageManagerLockFiles = {
'npm-shrinkwrap.json': 'npm-legacy',
'package-lock.json': 'npm',
'yarn.lock': 'yarn',
'pnpm-lock.yaml': 'pnpm'
} as const

type LockFile = keyof typeof PackageManagerLockFiles
type _PackageManager = typeof PackageManagerLockFiles[LockFile]
export type PackageManager = _PackageManager | 'unknown'

debug('distDir', distDir)
debug('runtimeDir', runtimeDir)
debug('pkgDir', pkgDir)
debug('pkgModulesDir', pkgModulesDir)

export async function getPackageManagerType(): Promise<PackageManager> {
try {
const parsed = parsePath(await resolveLockfile())
const lockfile = `${parsed.name}${parsed.ext}` as LockFile
debug('getPackageManagerType: lockfile', lockfile)
if (lockfile == null) {
return 'unknown'
}
const type = PackageManagerLockFiles[lockfile]
return type == null ? 'unknown' : type
} catch (e) {
debug('getPackageManagerType: resolveLockfile error', e)
throw e
}
}

export async function resolveVueI18nPkgPath() {
const p = await resolvePath('vue-i18n')
debug('vue-i18n resolved path', p)
return resolve(p, '../..')
}

export async function resolveVueI18nRoutingDtsPath(id: string) {
export async function resolveVueI18nRoutingDtsPath(id: string, rootDir: string) {
const pkgMgr = await getPackageManagerType()
if (pkgMgr === 'npm') {
debug('resolveVueI18nRoutingDtsPath on npm', `${VUE_I18N_ROUTING_PKG}/dist/${id}`)
return resolve(pkgModulesDir, `${VUE_I18N_ROUTING_PKG}/dist/${id}`)
} else if (pkgMgr === 'pnpm' || pkgMgr === 'yarn') {
const parsed = parsePath(await resolvePath(VUE_I18N_ROUTING_PKG))
debug(`resolveVueI18nRoutingDtsPath on ${pkgMgr}`, parsed)
return `${parsed.dir}/${id}`
} else {
throw new Error(`Not supported package manager`)
}
const dtsPath = `${VUE_I18N_ROUTING_PKG}/dist/${id}`
const targets = [
// 1st, try to resolve from `node_modules` (hoisted case)
resolve(rootDir, 'node_modules', dtsPath),
// 2nd, try to resolve from `node_modules/@nuxtjs/i18n` (not hoisted case)
resolve(pkgModulesDir, dtsPath)
]
debug(`${VUE_I18N_ROUTING_PKG} resolving from ...`, targets)

const resolved = await tryResolve(VUE_I18N_ROUTING_PKG, targets, pkgMgr, '.d.ts')
const parsed = parsePath(resolved)
return `${parsed.dir}/${parsed.name}`
}
4 changes: 2 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ export default defineNuxtModule<NuxtI18nOptions>({
: false
}
const nuxtAppExtendFilename = 'types/i18n-nuxt-app.d.ts'
const vueI18nRoutingVueI18nDtsPath = await resolveVueI18nRoutingDtsPath('vue-i18n')
const vueI18nRoutingMixinDtsPath = await resolveVueI18nRoutingDtsPath('vue')
const vueI18nRoutingVueI18nDtsPath = await resolveVueI18nRoutingDtsPath('vue-i18n', nuxt.options.rootDir)
const vueI18nRoutingMixinDtsPath = await resolveVueI18nRoutingDtsPath('vue', nuxt.options.rootDir)
addTemplate({
filename: nuxtAppExtendFilename,
getContents: () => {
Expand Down
48 changes: 47 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
import { promises as fs, constants as FS_CONSTANTS } from 'node:fs'
import { resolveFiles } from '@nuxt/kit'
import { parse } from 'pathe'
import { parse, parse as parsePath } from 'pathe'
import { encodePath } from 'ufo'
import { resolveLockfile } from 'pkg-types'
import { isObject, isString } from '@intlify/shared'
import { NUXT_I18N_MODULE_ID } from './constants'

import type { LocaleObject } from 'vue-i18n-routing'
import type { NuxtI18nOptions, LocaleInfo } from './types'

const PackageManagerLockFiles = {
'npm-shrinkwrap.json': 'npm-legacy',
'package-lock.json': 'npm',
'yarn.lock': 'yarn',
'pnpm-lock.yaml': 'pnpm'
} as const

type LockFile = keyof typeof PackageManagerLockFiles
type _PackageManager = typeof PackageManagerLockFiles[LockFile]
export type PackageManager = _PackageManager | 'unknown'

export async function getPackageManagerType(): Promise<PackageManager> {
try {
const parsed = parsePath(await resolveLockfile())
const lockfile = `${parsed.name}${parsed.ext}` as LockFile
if (lockfile == null) {
return 'unknown'
}
const type = PackageManagerLockFiles[lockfile]
return type == null ? 'unknown' : type
} catch (e) {
throw e
}
}

export function formatMessage(message: string) {
return `[${NUXT_I18N_MODULE_ID}]: ${message}`
}
Expand Down Expand Up @@ -39,6 +66,25 @@ export async function resolveLocales(path: string, locales: LocaleObject[]): Pro
})
}

export async function tryResolve(id: string, targets: string[], pkgMgr: PackageManager, extention = '') {
for (const target of targets) {
if (await isExists(target + extention)) {
return target
}
}

throw new Error(`Cannot resolve ${id} on ${pkgMgr}! please install it on 'node_modules'`)
}

async function isExists(path: string) {
try {
await fs.access(path, FS_CONSTANTS.F_OK)
return true
} catch (e) {
return false
}
}

/**
* sergment parser, forked from the below:
* - original repository url: https://github.com/nuxt/framework
Expand Down

0 comments on commit 563d636

Please sign in to comment.