feat: module utils and improvements (#38)

This commit is contained in:
pooya parsa 2021-04-02 13:47:01 +02:00 committed by GitHub
parent 1b9edfafb9
commit b3f3dc94f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 885 additions and 946 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ package-lock.json
dist
.nuxt*
.output
.gen
# Junit reports
reports

View File

@ -7,12 +7,13 @@
],
"scripts": {
"link": "lerna link",
"build": "yarn workspaces run build --silent",
"stub": "yarn workspaces run stub --silent",
"play": "yarn nu dev playground",
"lint": "eslint --ext .vue,.ts,.js .",
"test": "yarn lint",
"postinstall": "yarn stub"
"build": "yarn -s workspaces run build",
"stub": "yarn -s build --stub",
"gentypes": "yarn -s --cwd packages/kit gentypes",
"play": "yarn -s nu dev playground",
"lint": "yarn -s gentypes && eslint --ext .vue,.ts,.js .",
"test": "yarn -s lint",
"postinstall": "yarn -s stub"
},
"devDependencies": {
"@nuxtjs/eslint-config": "^6.0.0",
@ -26,10 +27,11 @@
"defu": "^3.2.2",
"esbuild": "^0.10.2",
"eslint": "^7.23.0",
"execa": "^5.0.0",
"jest": "^26.6.3",
"jiti": "^1.6.4",
"lerna": "^4.0.0",
"mkdist": "^0.1.2",
"mkdist": "^0.1.3",
"pretty-bytes": "^5.6.0",
"rimraf": "^3.0.2",
"rollup": "^2.43.1",

View File

@ -3,29 +3,22 @@
"version": "0.0.0",
"repository": "nuxt/framework",
"license": "MIT",
"main": "./dist/index.ts",
"main": "./dist/index.js",
"files": [
"dist"
],
"scripts": {
"build": "mkdist",
"stub": "rm -rf dist && ln -s src dist #",
"build": "jiti ../../scripts/build .",
"prepublishOnly": "yarn build"
},
"dependencies": {
"create-require": "^1.1.1",
"defu": "^3.2.2",
"dotenv": "^8.2.0",
"jiti": "^1.6.4",
"rc9": "^1.2.0",
"scule": "^0.1.1",
"std-env": "^2.3.0",
"ufo": "^0.6.10",
"untyped": "^0.2.2"
"hookable": "^4.4.1",
"vue": "^3.0.10"
},
"build": {
"entries": {
"index": {}
"index": { "distDir": ".gen" },
"/": {}
}
}
}

View File

@ -16,7 +16,7 @@ async function initApp () {
await app.$nuxt.hooks.callHook('app:created', app)
await app.$nuxt.hooks.callHook('app:beforeMount', app)
app.mount('#<%= globals.id %>')
app.mount('#__nuxt')
await app.$nuxt.hooks.callHook('app:mounted', app)
await nextTick()

View File

@ -1,10 +0,0 @@
declare module NodeJS {
interface Process {
browser: boolean
client: boolean
mode: 'spa' | 'universal'
modern: boolean
server: boolean
static: boolean
}
}

View File

@ -1,6 +0,0 @@
declare module 'nuxt/build/routes' {
import { RouteRecordRaw } from 'vue-router'
const _default: RouteRecordRaw[]
export default _default
}

View File

@ -1,5 +0,0 @@
declare module '*.vue' {
import { Component } from 'vue'
const component: Component
export default component
}

View File

@ -1,7 +0,0 @@
import { Nuxt } from '@nuxt/app'
declare module 'vue' {
interface App {
$nuxt: Nuxt
}
}

View File

@ -1,3 +0,0 @@
interface Window {
__NUXT__?: Record<string, any>
}

View File

@ -0,0 +1 @@
export * from './index.ts'

View File

@ -1,2 +1,4 @@
export { useNuxt } from './nuxt/composables'
export * from './nuxt'
export * from './shim'

View File

@ -1,5 +1,5 @@
import { getCurrentInstance } from 'vue'
import type { Nuxt } from '@nuxt/app'
import type { Nuxt } from '../nuxt'
let currentNuxtInstance: Nuxt | null

24
packages/app/src/shim.ts Normal file
View File

@ -0,0 +1,24 @@
import type { Nuxt } from './nuxt'
declare module 'vue' {
interface App {
$nuxt: Nuxt
}
}
declare global {
interface Window {
__NUXT__?: Record<string, any>
}
namespace NodeJS {
interface Process {
browser: boolean
client: boolean
mode: 'spa' | 'universal'
modern: boolean
server: boolean
static: boolean
}
}
}

View File

@ -10,24 +10,26 @@
],
"scripts": {
"build": "jiti ../../scripts/build .",
"genconfig": "jiti ./scripts/genconfig",
"stub": "yarn build --stub",
"prepublishOnly": "yarn build && yarn genconfig"
"gentypes": "jiti ./scripts/gentypes",
"prepublishOnly": "yarn build && yarn gentypes"
},
"dependencies": {
"consola": "^2.15.3",
"create-require": "^1.1.1",
"defu": "^3.2.2",
"dotenv": "^8.2.0",
"hash-sum": "^2.0.0",
"jiti": "^1.6.4",
"lodash": "^4.17.21",
"rc9": "^1.2.0",
"scule": "^0.1.1",
"std-env": "^2.3.0",
"ufo": "^0.6.10",
"untyped": "^0.2.2"
"unctx": "^0.0.3",
"untyped": "^0.2.2",
"upath": "^2.0.1"
},
"build": {
"prebuild": "yarn -s gentypes",
"entries": {
"index": {
"format": "cjs"

View File

@ -3,7 +3,7 @@ import { mkdir, writeFile } from 'fs/promises'
import { resolveSchema, generateTypes, generateMarkdown } from 'untyped'
async function main () {
const genDir = resolve(__dirname, '../dist/config')
const genDir = resolve(__dirname, '../.gen')
const srcConfig = await import('../src/config/schema').then(r => r.default)
const defaults = { rootDir: '/<dir>/' }
@ -11,9 +11,9 @@ async function main () {
await mkdir(genDir).catch(() => { })
await writeFile(resolve(genDir, 'config.md'), generateMarkdown(schema))
await writeFile(resolve(genDir, 'schema.json'), JSON.stringify(schema, null, 2))
await writeFile(resolve(genDir, 'defaults.json'), JSON.stringify(defaults, null, 2))
await writeFile(resolve(genDir, 'config.d.ts'), 'export default ' + generateTypes(schema, 'Config'))
await writeFile(resolve(genDir, 'config.schema.json'), JSON.stringify(schema, null, 2))
await writeFile(resolve(genDir, 'config.defaults.json'), JSON.stringify(defaults, null, 2))
await writeFile(resolve(genDir, 'config.d.ts'), 'export ' + generateTypes(schema, 'ConfigSchema'))
}
main().catch(console.error)

View File

@ -3,6 +3,7 @@ import defu from 'defu'
import jiti from 'jiti'
import { applyDefaults } from 'untyped'
import * as rc from 'rc9'
import { NuxtOptions } from '../types/config'
import nuxtConfigSchema from './schema'
export interface LoadNuxtConfigOptions {
@ -11,7 +12,7 @@ export interface LoadNuxtConfigOptions {
config?: any
}
export function loadNuxtConfig (opts: LoadNuxtConfigOptions) {
export function loadNuxtConfig (opts: LoadNuxtConfigOptions): NuxtOptions {
const rootDir = resolve(process.cwd(), opts.rootDir || '.')
const _require = jiti(rootDir)
@ -53,5 +54,5 @@ export function loadNuxtConfig (opts: LoadNuxtConfigOptions) {
}
// Resolve and apply defaults
return applyDefaults(nuxtConfigSchema, nuxtConfig)
return applyDefaults(nuxtConfigSchema, nuxtConfig) as NuxtOptions
}

View File

@ -112,10 +112,10 @@ export default {
},
extensions: {
$resolve: val => ['js', 'mjs', 'ts', 'tsx', 'vue'].concat(val).filter(Boolean)
$resolve: val => ['.js', '.mjs', '.ts', '.tsx', '.vue'].concat(val).filter(Boolean)
},
styleExtensions: ['css', 'pcss', 'postcss', 'styl', 'stylus', 'scss', 'sass', 'less'],
styleExtensions: ['.css', '.pcss', '.postcss', '.styl', '.stylus', '.scss', '.sass', '.less'],
alias: {
$resolve: (val, get) => ({

View File

@ -0,0 +1,11 @@
export default {
_majorVersion: 2,
_legacyGenerate: false,
_start: false,
_build: false,
_generate: false,
_cli: false,
_requiredModules: {},
appDir: '',
vite: false
}

View File

@ -1,6 +1,7 @@
import _app from './_app'
import _common from './_common'
import _internal from './_internal'
import build from './build'
import messages from './messages'
import render from './render'
@ -30,6 +31,7 @@ TODO for top level normalizations: (nuxt2)
export default {
..._app,
..._common,
..._internal,
build,
messages,
render,

View File

@ -1,3 +1,22 @@
// Config
export * from './config/load'
export * from './config/env'
export * from './utils'
// Nuxt
export * from './nuxt'
// Module
export * from './module/container'
export * from './module/define'
export * from './module/install'
export * from './module/utils'
// Utils
export * from './utils/cjs'
export * from './utils/resolve'
// Types
export * from './types/config'
export * from './types/hooks'
export * from './types/module'
export * from './types/nuxt'

View File

@ -0,0 +1,73 @@
import type { Nuxt } from '../types/nuxt'
import type { NuxtOptions } from '../types/config'
import type { TemplateOpts, PluginTemplateOpts } from '../types/module'
import { nuxtCtx } from '../nuxt'
import { installModule } from './install'
import {
addTemplate,
addErrorLayout,
addLayout,
addPlugin,
addServerMiddleware,
extendBuild,
extendRoutes
} from './utils'
export class ModuleContainer {
nuxt: Nuxt
options: NuxtOptions
constructor (nuxt: Nuxt) {
this.nuxt = nuxt
this.options = nuxt.options
}
private _call<F extends (...args: any) => any>(fn: F, ...args: Parameters<F>): ReturnType<F> {
// @ts-ignore
return nuxtCtx.call(this.nuxt, () => fn(...args))
}
ready () {
return Promise.resolve()
}
addVendor () {
console.warn('addVendor has been deprecated')
}
addTemplate (tmpl: TemplateOpts | string) {
return this._call(addTemplate, tmpl)
}
addPlugin (tmpl: PluginTemplateOpts) {
return this._call(addPlugin, tmpl)
}
addLayout (tmpl: TemplateOpts, name: string) {
return this._call(addLayout, tmpl, name)
}
addErrorLayout (dst: string) {
return this._call(addErrorLayout, dst)
}
addServerMiddleware (middleware) {
return this._call(addServerMiddleware, middleware)
}
extendBuild (fn) {
return this._call(extendBuild, fn)
}
extendRoutes (fn) {
return this._call(extendRoutes, fn)
}
requireModule (moduleOpts) {
return installModule(this.nuxt, moduleOpts)
}
addModule (moduleOpts) {
return installModule(this.nuxt, moduleOpts)
}
}

View File

@ -0,0 +1,44 @@
import defu from 'defu'
import { applyDefaults } from 'untyped'
import { useNuxt, nuxtCtx } from '../nuxt'
import type { Nuxt } from '../types/nuxt'
import type { NuxtModule, LegacyNuxtModule, ModuleOptions } from '../types/module'
export function defineNuxtModule<OptionsT extends ModuleOptions> (input: NuxtModule<OptionsT> | ((nuxt: Nuxt) => NuxtModule<OptionsT>)): LegacyNuxtModule {
let mod: NuxtModule<OptionsT>
function wrappedModule (inlineOptions: OptionsT) {
// Get nuxt context
const nuxt: Nuxt = this.nuxt || useNuxt()
// Resolve function
if (typeof input === 'function') {
const fn = input
mod = nuxtCtx.call(nuxt, () => fn(nuxt))
} else {
mod = input
}
// Install hooks
if (mod.hooks) {
nuxt.hooks.addHooks(mod.hooks)
}
// Stop if no install provided
if (typeof mod.setup !== 'function') {
return
}
// Resolve options
const configKey = mod.configKey || mod.name
const userOptions = defu(inlineOptions, nuxt.options[configKey]) as OptionsT
const resolvedOptions = applyDefaults(mod.defaults as any, userOptions) as OptionsT
// Call setup
return nuxtCtx.call(nuxt, () => mod.setup.call(null, resolvedOptions, nuxt))
}
wrappedModule.meta = mod
return wrappedModule
}

View File

@ -0,0 +1,60 @@
import type { Nuxt } from '../types/nuxt'
import type { LegacyNuxtModule, NuxtModule, ModuleMeta, ModuleInstallOptions, ModuleOptions, ModuleSrc } from '../types/module'
import { requireModule } from '../utils/cjs'
import { nuxtCtx } from '../nuxt'
import { defineNuxtModule } from './define'
import { ModuleContainer } from './container'
export async function installModule (nuxt: Nuxt, installOpts: ModuleInstallOptions) {
let src: ModuleSrc
let options: ModuleOptions = {}
const meta: ModuleMeta = {}
// Extract src, meta and options
if (typeof installOpts === 'string') {
src = installOpts
} else if (Array.isArray(installOpts)) {
[src, options] = installOpts
} else if (typeof installOpts === 'object') {
if (installOpts.src || installOpts.handler) {
src = installOpts.src || installOpts.handler
options = installOpts.options
Object.assign(meta, installOpts.meta)
} else {
src = installOpts as NuxtModule
}
} else {
src = installOpts
}
// Resolve as legacy handler
let handler: LegacyNuxtModule
if (typeof src === 'string') {
handler = requireModule(src)
if (!meta.name) {
meta.name = src
}
} else if (typeof src === 'function') {
handler = src
} else {
handler = defineNuxtModule(src)
}
// Merge meta
if (handler.meta) {
Object.assign(meta, handler.meta)
}
// Ensure module is required once
if (typeof meta.name === 'string') {
nuxt.options._requiredModules = nuxt.options._requiredModules || {}
if (nuxt.options._requiredModules[meta.name]) {
return
}
nuxt.options._requiredModules[meta.name] = true
}
// Execute in legacy container
const container = new ModuleContainer(nuxt)
await nuxtCtx.call(nuxt, () => handler.call(container, options))
}

View File

@ -0,0 +1,100 @@
import path, { basename, parse } from 'path'
import fs from 'fs'
import hash from 'hash-sum'
import consola from 'consola'
import { useNuxt } from '../nuxt'
import { chainFn } from '../utils/task'
import type { TemplateOpts, PluginTemplateOpts } from '../types/module'
export function addTemplate (tmpl: TemplateOpts | string) {
const nuxt = useNuxt()
if (!tmpl) {
throw new Error('Invalid tmpl: ' + JSON.stringify(tmpl))
}
// Validate & parse source
const src = typeof tmpl === 'string' ? tmpl : tmpl.src
const srcPath = parse(src)
if (typeof src !== 'string' || !fs.existsSync(src)) {
throw new Error('tmpl src not found: ' + src)
}
// Mostly for DX, some people prefers `filename` vs `fileName`
const fileName = typeof tmpl === 'string' ? '' : tmpl.fileName || tmpl.filename
// Generate unique and human readable dst filename if not provided
const dst = fileName || `${basename(srcPath.dir)}.${srcPath.name}.${hash(src)}${srcPath.ext}`
// Add to tmpls list
const tmplObj = {
src,
dst,
options: typeof tmpl === 'string' ? undefined : tmpl.options
}
nuxt.options.build.templates.push(tmplObj)
return tmplObj
}
export function addPlugin (tmpl: PluginTemplateOpts) {
const nuxt = useNuxt()
const { dst } = addTemplate(tmpl)
if (!tmpl.mode && typeof tmpl.ssr === 'boolean') {
tmpl.mode = tmpl.ssr ? 'server' : 'client'
}
// Add to nuxt plugins
nuxt.options.plugins.unshift({
src: path.join(nuxt.options.buildDir, dst),
mode: tmpl.mode
})
}
export function addLayout (tmpl: TemplateOpts, name: string) {
const nuxt = useNuxt()
const { dst, src } = addTemplate(tmpl)
const layoutName = name || path.parse(src).name
const layout = nuxt.options.layouts[layoutName]
if (layout) {
consola.warn(`Duplicate layout registration, "${layoutName}" has been registered as "${layout}"`)
}
// Add to nuxt layouts
nuxt.options.layouts[layoutName] = `./${dst}`
// If error layout, set ErrorPage
if (name === 'error') {
addErrorLayout(dst)
}
}
export function addErrorLayout (dst: string) {
const nuxt = useNuxt()
const relativeBuildDir = path.relative(nuxt.options.rootDir, nuxt.options.buildDir)
nuxt.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
}
export function addServerMiddleware (middleware) {
const nuxt = useNuxt()
nuxt.options.serverMiddleware.push(middleware)
}
export function extendBuild (fn) {
const nuxt = useNuxt()
// @ts-ignore TODO
nuxt.options.build.extend = chainFn(nuxt.options.build.extend, fn)
}
export function extendRoutes (fn) {
const nuxt = useNuxt()
nuxt.options.router.extendRoutes = chainFn(nuxt.options.router.extendRoutes, fn)
}

10
packages/kit/src/nuxt.ts Normal file
View File

@ -0,0 +1,10 @@
import { getContext } from 'unctx'
import type { Nuxt } from './types/nuxt'
import type { NuxtConfig } from './types/config'
export const nuxtCtx = getContext<Nuxt>('nuxt')
export const useNuxt = nuxtCtx.use
export function defineNuxtConfig (config: NuxtConfig) {
return config
}

View File

@ -0,0 +1,15 @@
import { ConfigSchema } from '../../.gen/config'
import { ModuleInstallOptions } from './module'
import { NuxtHooks } from './hooks'
export interface TypedConfigSchema extends ConfigSchema {
hooks: NuxtHooks,
modules: ModuleInstallOptions[]
buildModules: ModuleInstallOptions[]
}
export interface NuxtOptions extends TypedConfigSchema { }
type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]> | T[P] }
export interface NuxtConfig extends DeepPartial<TypedConfigSchema> { }

View File

@ -0,0 +1,13 @@
import { Nuxt } from './nuxt'
export type NuxtHook<Arg1 = any> = (arg1: Arg1, ...args: any) => Promise<void> | void
export interface NuxtHooks {
[key: string]: NuxtHook
'modules:before': NuxtHook<Nuxt>
'modules:done': NuxtHook<Nuxt>
'ready': NuxtHook<Nuxt>
}
export type NuxtHookName = keyof NuxtHooks

View File

@ -0,0 +1,51 @@
import type { ModuleContainer } from '../module/container'
import { Nuxt } from './nuxt'
import { NuxtHooks } from './hooks'
export interface ModuleMeta {
name?: string
configKey?: string
[key: string]: any
}
export type ModuleOptions = Record<string, any>
export interface LegacyNuxtModule {
(this: ModuleContainer, inlineOptions?: ModuleOptions): void | Promise<void>
meta?: ModuleMeta
}
export interface NuxtModule<T extends ModuleOptions = any> extends ModuleMeta {
defaults?: T
setup?: (this: null, resolvedOptions: T, nuxt: Nuxt) => void | Promise<void>
hooks?: Partial<NuxtHooks>
}
export type ModuleSrc = string | NuxtModule | LegacyNuxtModule
export interface ModuleInstallOptionsObj {
src: ModuleSrc,
meta: ModuleMeta
options: ModuleOptions
handler: LegacyNuxtModule
}
export type ModuleInstallOptions =
ModuleSrc |
[ModuleSrc, ModuleOptions?] |
Partial<ModuleInstallOptionsObj>
// -- Templates --
export interface TemplateOpts {
filename?: string
fileName?: string
options?: Record<string, any>
src: string
}
export interface PluginTemplateOpts extends TemplateOpts {
/** @deprecated use mode */
ssr?: boolean
mode?: 'all' | 'server' | 'client'
}

View File

@ -0,0 +1,16 @@
import { NuxtHookName, NuxtHook, NuxtHooks } from './hooks'
import { NuxtOptions } from './config'
export interface Nuxt {
options: NuxtOptions
hooks: {
hook(hookName: NuxtHookName, callback: NuxtHook)
callHook<T extends string>(hookbname: T, ...args: Parameters<NuxtHooks[T]>)
addHooks(hooks: Partial<NuxtHooks>)
}
hook: Nuxt['hooks']['hook']
callHook: Nuxt['hooks']['callHook']
server?: any
}

View File

@ -1,18 +1,33 @@
import { join } from 'path'
import jiti from 'jiti'
export function isExternalDependency (id: string) {
// TODO: use create-require for jest environment
const _require = jiti(process.cwd())
export interface ResolveModuleOptions {
paths?: string[]
}
export interface RequireModuleOptions extends ResolveModuleOptions {
native?: boolean
clearCache?: boolean
interopDefault?: boolean
}
export function isNodeModules (id: string) {
// TODO: Follow symlinks
return /[/\\]node_modules[/\\]/.test(id)
}
export function clearRequireCache (id: string) {
if (isExternalDependency(id)) {
if (isNodeModules(id)) {
return
}
const entry = getRequireCacheItem(id)
if (!entry) {
delete require.cache[id]
delete _require.cache[id]
return
}
@ -24,11 +39,11 @@ export function clearRequireCache (id: string) {
clearRequireCache(child.id)
}
delete require.cache[id]
delete _require.cache[id]
}
export function scanRequireTree (id: string, files = new Set<string>()) {
if (isExternalDependency(id) || files.has(id)) {
if (isNodeModules(id) || files.has(id)) {
return files
}
@ -50,18 +65,54 @@ export function scanRequireTree (id: string, files = new Set<string>()) {
export function getRequireCacheItem (id: string) {
try {
return require.cache[id]
return _require.cache[id]
} catch (e) {
}
}
export function tryRequire (id: string) {
export function requireModulePkg (id: string, opts: RequireModuleOptions = {}) {
return requireModule(join(id, 'package.json'), opts)
}
export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
return _require.resolve(id, {
paths: opts.paths
})
}
export function tryResolveModule (path: string, opts: ResolveModuleOptions = {}) {
try {
return require(id)
} catch (e) {
return resolveModule(path, opts)
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
throw error
}
}
}
export function getPKG (id: string) {
return tryRequire(join(id, 'package.json'))
export function requireModule (id: string, opts: RequireModuleOptions = {}) {
// Resolve id
const resolvedPath = resolveModule(id, opts)
// Clear require cache if necessary
if (opts.clearCache && !isNodeModules(id)) {
clearRequireCache(resolvedPath)
}
// Try to require
let requiredModule = _require(resolvedPath)
// Interop default
if (opts.interopDefault !== false && requiredModule && requiredModule.default) {
requiredModule = requiredModule.default
}
return requiredModule
}
export function tryRequireModule (id: string, opts: RequireModuleOptions = {}) {
try {
return requireModule(id, opts)
} catch (e) {
}
}

View File

@ -1,13 +0,0 @@
export const TARGETS = {
server: 'server',
static: 'static'
} as const
export type Target = keyof typeof TARGETS
export const MODES = {
universal: 'universal',
spa: 'spa'
} as const
export type Mode = keyof typeof MODES

View File

@ -1,36 +0,0 @@
import type { ServerResponse, IncomingMessage } from 'http'
import { TARGETS } from './constants'
export const getContext = function getContext (req: IncomingMessage, res: ServerResponse) {
return { req, res }
}
type NuxtGlobal = string | ((globalName: string) => string)
type Globals = 'id' | 'nuxt' | 'context' | 'pluginPrefix' | 'readyCallback' | 'loadedCallback'
type NuxtGlobals = {
[key in Globals]: NuxtGlobal
}
export type DeterminedGlobals = {
[key in keyof NuxtGlobals]: string
}
export const determineGlobals = function determineGlobals (globalName: string, globals: NuxtGlobals) {
const _globals: Partial<DeterminedGlobals> = {}
for (const global in globals) {
const currentGlobal = globals[global]
if (currentGlobal instanceof Function) {
_globals[global] = currentGlobal(globalName)
} else {
_globals[global] = currentGlobal
}
}
return _globals as DeterminedGlobals
}
export const isFullStatic = function (options) {
return !options.dev && !options._legacyGenerate && options.target === TARGETS.static && options.render.ssr
}

View File

@ -1,7 +0,0 @@
export * from './context'
export * from './lang'
export * from './resolve'
export * from './route'
export * from './task'
export * from './cjs'
export * from './constants'

View File

@ -1,47 +0,0 @@
export const encodeHtml = function encodeHtml (str: string) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;')
}
export const isString = (obj: unknown): obj is string =>
typeof obj === 'string' || obj instanceof String
export const isNonEmptyString = (obj: unknown): obj is string =>
Boolean(obj && isString(obj))
export const isPureObject = (
obj: unknown
): obj is Exclude<object, Array<any>> =>
!Array.isArray(obj) && typeof obj === 'object'
export const isUrl = function isUrl (url: string) {
return ['http', '//'].some(str => url.startsWith(str))
}
export const urlJoin = function urlJoin (...args: string[]) {
return [].slice
.call(args)
.join('/')
.replace(/\/+/g, '/')
.replace(':/', '://')
}
/**
* Wraps value in array if it is not already an array
*/
export const wrapArray = <T>(value: T | T[]): T[] =>
Array.isArray(value) ? value : [value]
const WHITESPACE_REPLACEMENTS: [RegExp, string][] = [
[/[ \t\f\r]+\n/g, '\n'], // strip empty indents
[/{\n{2,}/g, '{\n'], // strip start padding from blocks
[/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks
[/\n{3,}/g, '\n\n'], // strip multiple blank lines (1 allowed)
[/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed)
]
export const stripWhitespace = function stripWhitespace (string: string) {
WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => {
string = string.replace(regex, newSubstr)
})
return string
}

View File

@ -1,123 +1,72 @@
import path from 'path'
import consola from 'consola'
import escapeRegExp from 'lodash/escapeRegExp'
import { existsSync, lstatSync } from 'fs'
import { resolve, join } from 'upath'
export const startsWithAlias = (aliasArray: string[]) => (str: string) =>
aliasArray.some(c => str.startsWith(c))
export const startsWithSrcAlias = startsWithAlias(['@', '~'])
export const startsWithRootAlias = startsWithAlias(['@@', '~~'])
export const isWindows = process.platform.startsWith('win')
export const wp = function wp (p = '') {
if (isWindows) {
return p.replace(/\\/g, '\\\\')
}
return p
export interface ResolveOptions {
base?: string
alias?: Record<string, string>
extensions?: string[]
}
// Kept for backward compat (modules may use it from template context)
export const wChunk = function wChunk (p = '') {
return p
}
const reqSep = /\//g
const sysSep = escapeRegExp(path.sep)
const normalize = (string: string) => string.replace(reqSep, sysSep)
export const r = function r (...args: string[]) {
const lastArg = args[args.length - 1]
if (startsWithSrcAlias(lastArg)) {
return wp(lastArg)
function resolvePath (path: string, opts: ResolveOptions = {}) {
// Fast return in case of path exists
if (existsSync(path)) {
return path
}
return wp(path.resolve(...args.map(normalize)))
}
let resolvedPath: string
export const relativeTo = function relativeTo (dir: string, ...args: string[]): string {
// Keep webpack inline loader intact
if (args[0].includes('!')) {
const loaders = args.shift()!.split('!')
return loaders.concat(relativeTo(dir, loaders.pop()!, ...args)).join('!')
// Resolve alias
if (opts.alias) {
resolvedPath = resolveAlias(path, opts.alias)
}
// Resolve path
const resolvedPath = r(...args)
// Resolve relative to base or cwd
resolvedPath = resolve(opts.base || '.', resolvedPath)
// Check if path is an alias
if (startsWithSrcAlias(resolvedPath)) {
// Check if resolvedPath is a file
let isDirectory = false
if (existsSync(resolvedPath)) {
isDirectory = lstatSync(resolvedPath).isDirectory()
if (!isDirectory) {
return resolvedPath
}
}
// Check possible extensions
for (const ext of opts.extensions) {
// resolvedPath.[ext]
const resolvedPathwithExt = resolvedPath + ext
if (!isDirectory && existsSync(resolvedPathwithExt)) {
return resolvedPathwithExt
}
// resolvedPath/index.[ext]
const resolvedPathwithIndex = join(resolvedPath, 'index' + ext)
if (isDirectory && existsSync(resolvedPathwithIndex)) {
return resolvedPathwithIndex
}
}
// If extension check fails and resolvedPath is a valid directory, return it
if (isDirectory) {
return resolvedPath
}
// Make correct relative path
let rp = path.relative(dir, resolvedPath)
if (rp[0] !== '.') {
rp = '.' + path.sep + rp
}
return wp(rp)
// Give up if it is neither a directory
throw new Error(`Cannot resolve "${path}" from "${resolvedPath}"`)
}
interface AliasOptions {
bind?: boolean
warn?: boolean
export function resolveAlias (path: string, alias: ResolveOptions['alias']) {
for (const key in alias) {
if (path.startsWith(key)) {
path = alias[key] + path.substr(key.length)
}
}
return path
}
export function defineAlias <O extends Record<string, any>> (
src: O,
target: Record<string, any>,
prop: string | string[],
opts: AliasOptions = {}
) {
const { bind = true, warn = false } = opts
if (Array.isArray(prop)) {
for (const p of prop) {
defineAlias(src, target, p, opts)
export function tryResolvePath (path: string, opts: ResolveOptions = {}) {
try {
return resolvePath(path, opts)
} catch (e) {
}
return
}
let targetVal = target[prop]
if (bind && typeof targetVal === 'function') {
targetVal = targetVal.bind(target)
}
let warned = false
Object.defineProperty(src, prop, {
get: () => {
if (warn && !warned) {
warned = true
consola.warn({
message: `'${prop}' is deprecated'`,
// eslint-disable-next-line unicorn/error-message
additional: new Error().stack.split('\n').splice(2).join('\n')
})
}
return targetVal
}
})
}
const isIndex = (s: string) => /(.*)\/index\.[^/]+$/.test(s)
export function isIndexFileAndFolder (pluginFiles: string[]) {
// Return early in case the matching file count exceeds 2 (index.js + folder)
if (pluginFiles.length !== 2) {
return false
}
return pluginFiles.some(isIndex)
}
export const getMainModule = () => {
return (
require.main ||
(module && ((module as any).main as NodeJS.Module)) ||
module
)
}

View File

@ -1,25 +0,0 @@
import path from 'path'
import get from 'lodash/get'
import consola from 'consola'
// Guard dir1 from dir2 which can be indiscriminately removed
export const guardDir = function guardDir (options: Record<string, any>, key1: string, key2: string) {
const dir1 = get(options, key1, false) as string
const dir2 = get(options, key2, false) as string
if (
dir1 &&
dir2 &&
(
dir1 === dir2 ||
(
dir1.startsWith(dir2) &&
!path.basename(dir1).startsWith(path.basename(dir2))
)
)
) {
const errorMessage = `options.${key2} cannot be a parent of or same as ${key1}`
consola.fatal(errorMessage)
throw new Error(errorMessage)
}
}

View File

@ -1,4 +1,4 @@
export const sequence = function sequence<T, R> (
export function sequence<T, R> (
tasks: T[],
fn: (task: T) => R
) {
@ -8,14 +8,14 @@ export const sequence = function sequence<T, R> (
)
}
export const parallel = function parallel<T, R> (
export function parallel<T, R> (
tasks: T[],
fn: (task: T) => R
) {
return Promise.all(tasks.map(fn))
}
export const chainFn = function chainFn (base, fn) {
export function chainFn (base, fn) {
if (typeof fn !== 'function') {
return base
}

View File

@ -9,13 +9,19 @@
],
"scripts": {
"build": "jiti ../../scripts/build .",
"stub": "yarn build --stub",
"prepublishOnly": "yarn build"
},
"build": {
"externals": [
"@nuxt/kit"
],
"entries": {
"index": { "format": "cjs" },
"compat": { "format": "cjs" },
"index": {
"format": "cjs"
},
"compat": {
"format": "cjs"
},
"runtime/": {}
},
"dependencies": [
@ -77,6 +83,7 @@
"serve-static": "^1.14.1",
"std-env": "^2.3.0",
"table": "^6.0.7",
"ufo": "^0.6.10",
"upath": "^2.0.1",
"vue-bundle-renderer": "^0.2.3",
"vue-server-renderer": "^2.6.12"

View File

@ -57,8 +57,7 @@ export default function nuxt2CompatModule () {
// Resolve middleware
nuxt.hook('modules:done', () => {
const { middleware, legacyMiddleware } =
resolveMiddleware(nuxt.options.serverMiddleware, nuxt.resolver.resolvePath)
const { middleware, legacyMiddleware } = resolveMiddleware(nuxt.options.serverMiddleware)
if (nuxt.server) {
nuxt.server.setLegacyMiddleware(legacyMiddleware)
}

View File

@ -1,6 +1,6 @@
import { resolve } from 'upath'
import { resolve, dirname } from 'upath'
import defu from 'defu'
import type { NuxtOptions } from '@nuxt/types'
import type { NuxtOptions } from '@nuxt/kit'
import Hookable, { configHooksT } from 'hookable'
import type { Preset } from '@nuxt/un'
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
@ -106,7 +106,7 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
}
},
_internal: {
runtimeDir: resolve(__dirname, './runtime'),
runtimeDir: resolve(dirname(require.resolve('@nuxt/nitro')), 'runtime'),
hooks: new Hookable()
}
}

View File

@ -27,6 +27,11 @@ export function externals (opts: NodeExternalsOptions): Plugin {
return null
}
// Bundle ts
if (id.endsWith('.ts')) {
return null
}
for (const dir of opts.moduleDirectories) {
if (id.startsWith(dir)) {
id = id.substr(dir.length + 1)

View File

@ -2,6 +2,7 @@ import { resolve, join, extname } from 'upath'
import { joinURL } from 'ufo'
import globby from 'globby'
import { watch } from 'chokidar'
import { tryResolvePath } from '@nuxt/kit'
export interface ServerMiddleware {
route: string
@ -50,7 +51,7 @@ export function scanMiddleware (serverDir: string, onChange?: (results: ServerMi
return scan()
}
export function resolveMiddleware (serverMiddleware: any[], resolvePath: (string) => string) {
export function resolveMiddleware (serverMiddleware: any[]) {
const middleware: ServerMiddleware[] = []
const legacyMiddleware: ServerMiddleware[] = []
@ -65,7 +66,9 @@ export function resolveMiddleware (serverMiddleware: any[], resolvePath: (string
delete m.path
middleware.push({
...m,
handle: resolvePath(handle),
handle: tryResolvePath(handle, {
extensions: ['.ts', '.js']
}),
route
})
}

View File

@ -13,10 +13,12 @@
],
"scripts": {
"build": "jiti ../../scripts/build .",
"stub": "yarn build --stub",
"prepublishOnly": "yarn build"
},
"build": {
"externals": [
"nuxt3"
],
"entries": {
"index": { "format": "cjs" }
}

View File

@ -15,7 +15,10 @@ async function _main () {
const { loadNuxt, build } = await import('nuxt3')
const nuxt = await loadNuxt({ for: isDev ? 'dev' : 'build', rootDir })
const nuxt = await loadNuxt({
for: isDev ? 'dev' : 'build',
rootDir
})
if (isDev) {
// https://github.com/nuxt-contrib/listhen

View File

@ -9,7 +9,6 @@
],
"scripts": {
"build": "jiti ../../scripts/build .",
"stub": "yarn build --stub",
"prepublishOnly": "yarn build"
},
"build": {
@ -17,6 +16,7 @@
"index": { "format": "cjs" }
},
"dependencies": [
"@nuxt/app",
"@vue/compiler-sfc",
"postcss",
"postcss-loader",
@ -38,6 +38,7 @@
]
},
"dependencies": {
"@nuxt/kit": "0.0.0",
"@nuxt/app": "0.0.0",
"@nuxt/friendly-errors-webpack-plugin": "^2.5.0",
"@nuxt/nitro": "^0.1.11",
@ -50,12 +51,9 @@
"chokidar": "^3.5.1",
"consola": "^2.15.3",
"core-js": "^3.9.1",
"create-require": "^1.1.1",
"css-loader": "^5.2.0",
"css-minimizer-webpack-plugin": "^1.3.0",
"defu": "^3.2.2",
"destr": "^1.1.0",
"dotenv": "^8.2.0",
"esbuild-loader": "^2.11.0",
"file-loader": "^6.2.0",
"fs-extra": "^9.1.0",
@ -64,7 +62,6 @@
"hash-sum": "^2.0.0",
"hookable": "^4.4.1",
"ignore": "^5.1.8",
"jiti": "^1.6.4",
"lodash": "^4.17.21",
"memfs": "^3.2.0",
"mini-css-extract-plugin": "^1.4.0",
@ -72,9 +69,7 @@
"postcss": "^8.2.8",
"postcss-import-resolver": "^2.0.0",
"postcss-loader": "^5.2.0",
"rc9": "^1.2.0",
"scule": "^0.1.1",
"std-env": "3.0.0-alpha",
"style-resources-loader": "^1.4.1",
"time-fix-plugin": "^2.0.7",
"ufo": "^0.6.10",

View File

@ -1,8 +1,10 @@
import { resolve } from 'path'
import defu from 'defu'
import { tryResolvePath } from '@nuxt/kit'
import { Builder } from './builder'
import { NuxtRoute, resolvePagesRoutes } from './pages'
import { NuxtPlugin, resolvePlugins } from './plugins'
export interface NuxtApp {
main?: string
routes: NuxtRoute[]
@ -35,10 +37,15 @@ export async function createApp (
})
// Resolve app.main
const resolveOptions = {
base: nuxt.options.srcDir,
alias: nuxt.options.alias,
extensions: nuxt.options.extensions
}
if (!app.main) {
app.main =
nuxt.resolver.tryResolvePath('~/App') ||
nuxt.resolver.tryResolvePath('~/app')
app.main = tryResolvePath('~/App', resolveOptions) ||
tryResolvePath('~/app', resolveOptions)
}
// Resolve pages/

View File

@ -1,8 +1,8 @@
import { join, relative } from 'path'
import fsExtra from 'fs-extra'
import { debounce } from 'lodash'
import { DeterminedGlobals, determineGlobals } from '@nuxt/kit'
import { Nuxt } from './nuxt'
import { Nuxt } from '@nuxt/kit'
import {
templateData,
compileTemplates,
@ -15,14 +15,13 @@ import Ignore from './utils/ignore'
export class Builder {
nuxt: Nuxt
globals: DeterminedGlobals
globals: any
ignore: Ignore
templates: NuxtTemplate[]
app: NuxtApp
constructor (nuxt) {
this.nuxt = nuxt
this.globals = determineGlobals(nuxt.options.globalName, nuxt.options.globals)
this.ignore = new Ignore({
rootDir: nuxt.options.srcDir,
ignoreArray: nuxt.options.ignore.concat(
@ -53,7 +52,7 @@ async function _build (builder: Builder) {
await bundle(builder)
await nuxt.callHook('build:done')
await nuxt.callHook('build:done', builder)
}
function watch (builder: Builder) {

View File

@ -1,2 +1,2 @@
export { Nuxt, loadNuxt } from './nuxt'
export { build } from './builder'
export * from './nuxt'
export * from './builder'

View File

@ -1,235 +0,0 @@
import path from 'path'
import fs from 'fs'
import hash from 'hash-sum'
import consola from 'consola'
import { chainFn, sequence } from '@nuxt/kit'
import Nuxt from './nuxt'
interface TemplateInput {
filename?: string
fileName?: string
options?: Record<string, any>
src: string
ssr?: boolean
mode?: 'all' | 'server' | 'client'
}
export default class ModuleContainer {
nuxt: Nuxt
options: Nuxt['options']
requiredModules: Record<string, {
src: string
options: Record<string, any>
handler
}>
constructor (nuxt: Nuxt) {
this.nuxt = nuxt
this.options = nuxt.options
this.requiredModules = {}
// Self bind to allow destructre from container
for (const method of Object.getOwnPropertyNames(ModuleContainer.prototype)) {
if (typeof this[method] === 'function') {
this[method] = this[method].bind(this)
}
}
}
async ready () {
// Call before hook
await this.nuxt.callHook('modules:before', this, this.options.modules)
if (this.options.buildModules && !this.options._start) {
// Load every devModule in sequence
await sequence(this.options.buildModules, this.addModule)
}
// Load every module in sequence
await sequence(this.options.modules, this.addModule)
// Load ah-hoc modules last
await sequence(this.options._modules, this.addModule)
// Call done hook
await this.nuxt.callHook('modules:done', this)
}
addVendor () {
consola.warn('addVendor has been deprecated due to webpack4 optimization')
}
addTemplate (template: TemplateInput | string) {
if (!template) {
throw new Error('Invalid template: ' + JSON.stringify(template))
}
// Validate & parse source
const src = typeof template === 'string' ? template : template.src
const srcPath = path.parse(src)
if (typeof src !== 'string' || !fs.existsSync(src)) {
throw new Error('Template src not found: ' + src)
}
// Mostly for DX, some people prefers `filename` vs `fileName`
const fileName = typeof template === 'string' ? '' : template.fileName || template.filename
// Generate unique and human readable dst filename if not provided
const dst = fileName || `${path.basename(srcPath.dir)}.${srcPath.name}.${hash(src)}${srcPath.ext}`
// Add to templates list
const templateObj = {
src,
dst,
options: typeof template === 'string' ? undefined : template.options
}
this.options.build.templates.push(templateObj)
return templateObj
}
addPlugin (template: TemplateInput) {
const { dst } = this.addTemplate(template)
// Add to nuxt plugins
this.options.plugins.unshift({
src: path.join(this.options.buildDir, dst),
// TODO: remove deprecated option in Nuxt 3
ssr: template.ssr,
mode: template.mode
})
}
addLayout (template: TemplateInput, name: string) {
const { dst, src } = this.addTemplate(template)
const layoutName = name || path.parse(src).name
const layout = this.options.layouts[layoutName]
if (layout) {
consola.warn(`Duplicate layout registration, "${layoutName}" has been registered as "${layout}"`)
}
// Add to nuxt layouts
this.options.layouts[layoutName] = `./${dst}`
// If error layout, set ErrorPage
if (name === 'error') {
this.addErrorLayout(dst)
}
}
addErrorLayout (dst: string) {
const relativeBuildDir = path.relative(this.options.rootDir, this.options.buildDir)
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
}
addServerMiddleware (middleware) {
this.options.serverMiddleware.push(middleware)
}
extendBuild (fn) {
this.options.build.extend = chainFn(this.options.build.extend, fn)
}
extendRoutes (fn) {
this.options.router.extendRoutes = chainFn(
this.options.router.extendRoutes,
fn
)
}
requireModule (moduleOpts) {
return this.addModule(moduleOpts)
}
async addModule (moduleOpts) {
let src
let options: Record<string, any>
let handler
// Type 1: String or Function
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
src = moduleOpts
} else if (Array.isArray(moduleOpts)) {
// Type 2: Babel style array
[src, options] = moduleOpts
} else if (typeof moduleOpts === 'object') {
// Type 3: Pure object
({ src, options, handler } = moduleOpts)
}
// Define handler if src is a function
if (src instanceof Function) {
handler = src
}
// Prevent adding buildModules-listed entries in production
if (this.options.buildModules.includes(handler) && this.options._start) {
return
}
// Resolve handler
if (!handler && typeof src === 'string') {
try {
handler = this.nuxt.resolver.requireModule(src, { useESM: true })
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
throw error
}
// Hint only if entrypoint is not found and src is not local alias or path
if (error.message.includes(src) && !/^[~.]|^@\//.test(src)) {
let message = 'Module `{name}` not found.'
if (this.options.buildModules.includes(src)) {
message += ' Please ensure `{name}` is in `devDependencies` and installed. HINT: During build step, for npm/yarn, `NODE_ENV=production` or `--production` should NOT be used.'.replace('{name}', src)
} else if (this.options.modules.includes(src)) {
message += ' Please ensure `{name}` is in `dependencies` and installed.'
}
message = message.replace(/{name}/g, src)
consola.warn(message)
}
if (this.options._cli) {
throw error
} else {
// TODO: Remove in next major version
consola.warn('Silently ignoring module as programatic usage detected.')
return
}
}
}
// Validate handler
if (typeof handler !== 'function') {
throw new TypeError('Module should export a function: ' + src)
}
// Ensure module is required once
if ('meta' in handler && typeof src === 'string') {
const metaKey = handler.meta && handler.meta.name
const key = metaKey || src
if (typeof key === 'string') {
if (this.requiredModules[key]) {
if (!metaKey) {
// TODO: Skip with nuxt3
consola.warn('Modules should be only specified once:', key)
} else {
return
}
}
this.requiredModules[key] = { src, options, handler }
}
}
// Default module options to empty object
if (options === undefined) {
options = {}
}
const result = await handler.call(this, options)
return result
}
}

View File

@ -1,19 +1,18 @@
// eslint-disable-next-line import/named
import { wpfs, getNitroContext, createDevServer, resolveMiddleware, build, prepare, generate } from '@nuxt/nitro'
import type { Nuxt } from './index'
import type { Nuxt } from '@nuxt/kit'
export function initNitro (nuxt: Nuxt) {
// Create contexts
const nitroContext = getNitroContext(nuxt.options, nuxt.options.nitro || {})
const nitroContext = getNitroContext(nuxt.options, (nuxt.options as any).nitro || {})
const nitroDevContext = getNitroContext(nuxt.options, { preset: 'dev' })
nuxt.server = createDevServer(nitroDevContext)
// Connect hooks
nuxt.addHooks(nitroContext.nuxtHooks)
nuxt.hooks.addHooks(nitroContext.nuxtHooks)
nuxt.hook('close', () => nitroContext._internal.hooks.callHook('close'))
nuxt.addHooks(nitroDevContext.nuxtHooks)
nuxt.hooks.addHooks(nitroDevContext.nuxtHooks)
nuxt.hook('close', () => nitroDevContext._internal.hooks.callHook('close'))
// Expose process.env.NITRO_PRESET
@ -21,8 +20,7 @@ export function initNitro (nuxt: Nuxt) {
// Resolve middleware
nuxt.hook('modules:done', () => {
const { middleware, legacyMiddleware } =
resolveMiddleware(nuxt.options.serverMiddleware, nuxt.resolver.resolvePath)
const { middleware, legacyMiddleware } = resolveMiddleware(nuxt.options.serverMiddleware)
nuxt.server.setLegacyMiddleware(legacyMiddleware)
nitroContext.middleware.push(...middleware)
nitroDevContext.middleware.push(...middleware)
@ -39,7 +37,7 @@ export function initNitro (nuxt: Nuxt) {
}
})
// nude dev
// nuxt dev
if (nuxt.options.dev) {
nitroDevContext._internal.hooks.hook('nitro:compiled', () => { nuxt.server.watch() })
nuxt.hook('build:compile', ({ compiler }) => { compiler.outputFileSystem = wpfs })

View File

@ -1,107 +1,64 @@
import type { IncomingHttpHeaders } from 'http'
import { dirname } from 'path'
import isPlainObject from 'lodash/isPlainObject'
import consola from 'consola'
import Hookable from 'hookable'
import { LoadNuxtOptions, loadNuxtConfig } from '@nuxt/kit'
import { version } from '../package.json'
import ModuleContainer from './module'
import Resolver from './resolver'
import { loadNuxtConfig, LoadNuxtConfigOptions, Nuxt, NuxtOptions, installModule } from '@nuxt/kit'
import { initNitro } from './nitro'
declare global {
namespace NodeJS {
interface Global {
__NUXT_DEV__: boolean
}
export function createNuxt (options: NuxtOptions): Nuxt {
const hooks = new Hookable()
return {
options,
hooks,
callHook: hooks.callHook,
hook: hooks.hook
}
}
export class Nuxt extends Hookable {
_ready?: Promise<this>
_initCalled?: boolean
async function initNuxt (nuxt: Nuxt) {
// Register user hooks
nuxt.hooks.addHooks(nuxt.options.hooks)
error?: Error & { statusCode?: number, headers?: IncomingHttpHeaders }
options: any
resolver: Resolver
moduleContainer: ModuleContainer
server?: any
renderer?: any
render?: any['app']
showReady?: () => void
// Init nitro
await initNitro(nuxt)
constructor (options) {
super(consola)
// Init user modules
await nuxt.callHook('modules:before', nuxt)
const modulesToInstall = [
...nuxt.options.buildModules,
...nuxt.options.modules,
...nuxt.options._modules
]
this.options = options
for (const m of modulesToInstall) {
await installModule(nuxt, m)
}
// Create instance of core components
this.resolver = new Resolver(this)
this.moduleContainer = new ModuleContainer(this)
await nuxt.callHook('modules:done', nuxt)
// Call ready
if (this.options._ready !== false) {
this.ready().catch((err) => {
consola.fatal(err)
await nuxt.callHook('ready', nuxt)
}
export interface LoadNuxtOptions extends LoadNuxtConfigOptions {
for?: 'dev' | 'build'
}
export async function loadNuxt (loadOpts: LoadNuxtOptions = {}): Promise<Nuxt> {
const options = loadNuxtConfig({
config: {
dev: loadOpts.for === 'dev',
...loadOpts.config
},
...loadOpts
})
}
}
static get version () {
return `v${version}` + (global.__NUXT_DEV__ ? '-development' : '')
}
ready () {
if (!this._ready) {
this._ready = this._init()
}
return this._ready
}
async _init () {
if (this._initCalled) {
return this
}
this._initCalled = true
// Add hooks
if (this.options.hooks instanceof Function) {
this.options.hooks(this.hook)
} else if (isPlainObject(this.options.hooks)) {
this.addHooks(this.options.hooks)
}
// Await for server
await initNitro(this)
// Await for modules
await this.moduleContainer.ready()
// Call ready hook
await this.callHook('ready', this)
return this
}
async close (callback?: () => any | Promise<any>) {
await this.callHook('close', this)
if (typeof callback === 'function') {
await callback()
}
}
}
export async function loadNuxt (opts: LoadNuxtOptions) {
const options = await loadNuxtConfig(opts)
// Temp
// @ts-ignore
options.appDir = dirname(require.resolve('@nuxt/app'))
options._majorVersion = 3
const nuxt = new Nuxt(options)
await nuxt.ready()
const nuxt = createNuxt(options)
await initNuxt(nuxt)
return nuxt
}

View File

@ -32,7 +32,7 @@ interface SegmentToken {
export async function resolvePagesRoutes (builder: Builder, app: NuxtApp) {
const pagesDir = resolve(app.dir, app.pages!.dir)
const pagesPattern = `${app.pages!.dir}/**/*.{${app.extensions.join(',')}}`
const pagesPattern = `${app.pages!.dir}/**/*{${app.extensions.join(',')}}`
const files = await resolveFiles(builder, pagesPattern, app.dir)
// Sort to make sure parent are listed first

View File

@ -1,186 +0,0 @@
import { resolve, join } from 'path'
import fs from 'fs-extra'
import jiti from 'jiti'
import {
startsWithRootAlias,
startsWithSrcAlias,
isExternalDependency,
clearRequireCache
} from '@nuxt/kit'
import { Nuxt } from './nuxt'
interface ResolvePathOptions {
isAlias?: boolean
isModule?: boolean
isStyle?: boolean
}
interface RequireModuleOptions {
useESM?: boolean
isAlias?: boolean
interopDefault?: any
}
export default class Resolver {
_require: NodeJS.Require
_resolve: NodeJS.RequireResolve
nuxt: Nuxt
options: Nuxt['options']
constructor (nuxt: Nuxt) {
this.nuxt = nuxt
this.options = this.nuxt.options
// Binds
this.resolvePath = this.resolvePath.bind(this)
this.resolveAlias = this.resolveAlias.bind(this)
this.resolveModule = this.resolveModule.bind(this)
this.requireModule = this.requireModule.bind(this)
this._require = jiti(__filename)
this._resolve = this._require.resolve
}
resolveModule (path: string) {
try {
return this._resolve(path, {
paths: this.options.modulesDir
})
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
// TODO: remove after https://github.com/facebook/jest/pull/8487 released
if (process.env.NODE_ENV === 'test' && error.message.startsWith('Cannot resolve module')) {
return
}
throw error
}
}
}
resolveAlias (path: string) {
if (startsWithRootAlias(path)) {
return join(this.options.rootDir, path.substr(2))
}
if (startsWithSrcAlias(path)) {
return join(this.options.srcDir, path.substr(1))
}
return resolve(this.options.srcDir, path)
}
resolvePath (path: string, { isAlias, isModule, isStyle }: ResolvePathOptions = {}) {
// Fast return in case of path exists
if (fs.existsSync(path)) {
return path
}
let resolvedPath: string
// Try to resolve it as a regular module
if (isModule !== false) {
resolvedPath = this.resolveModule(path)
}
// Try to resolve alias
if (!resolvedPath && isAlias !== false) {
resolvedPath = this.resolveAlias(path)
}
// Use path for resolvedPath
if (!resolvedPath) {
resolvedPath = path
}
let isDirectory: boolean
// Check if resolvedPath exits and is not a directory
if (fs.existsSync(resolvedPath)) {
isDirectory = fs.lstatSync(resolvedPath).isDirectory()
if (!isDirectory) {
return resolvedPath
}
}
const extensions = isStyle ? this.options.styleExtensions : this.options.extensions
// Check if any resolvedPath.[ext] or resolvedPath/index.[ext] exists
for (const ext of extensions) {
if (!isDirectory && fs.existsSync(resolvedPath + '.' + ext)) {
return resolvedPath + '.' + ext
}
const resolvedPathwithIndex = join(resolvedPath, 'index.' + ext)
if (isDirectory && fs.existsSync(resolvedPathwithIndex)) {
return resolvedPathwithIndex
}
}
// If there's no index.[ext] we just return the directory path
if (isDirectory) {
return resolvedPath
}
// Give up
throw new Error(`Cannot resolve "${path}" from "${resolvedPath}"`)
}
tryResolvePath (path: string, options?: ResolvePathOptions) {
try {
return this.resolvePath(path, options)
} catch (e) {
}
}
requireModule <T> (path: string, { useESM, isAlias, interopDefault }: RequireModuleOptions = {}): T {
let resolvedPath = path
let requiredModule: any
let lastError: any
// Try to resolve path
try {
resolvedPath = this.resolvePath(path, { isAlias })
} catch (e) {
lastError = e
}
const isExternal = isExternalDependency(resolvedPath)
// in dev mode make sure to clear the require cache so after
// a dev server restart any changed file is reloaded
if (this.options.dev && !isExternal) {
clearRequireCache(resolvedPath)
}
// By default use esm only for js,mjs files outside of node_modules
if (useESM === undefined) {
useESM = !isExternal && /.(js|mjs)$/.test(resolvedPath)
}
// Try to require
try {
if (useESM) {
requiredModule = this._require(resolvedPath)
} else {
requiredModule = require(resolvedPath)
}
} catch (e) {
lastError = e
}
// Interop default
if (interopDefault !== false && requiredModule && requiredModule.default) {
requiredModule = requiredModule.default
}
// Throw error if failed to require
if (requiredModule === undefined && lastError) {
throw lastError
}
return requiredModule
}
}

View File

@ -19,10 +19,16 @@ export function templateData (builder) {
}
}
async function compileTemplate ({ src, path, data }: NuxtTemplate, destDir: string) {
const srcContents = await fsExtra.readFile(src, 'utf-8')
const compiledSrc = lodashTemplate(srcContents, {})(data)
const dest = join(destDir, path)
async function compileTemplate (tmpl: NuxtTemplate, destDir: string) {
const srcContents = await fsExtra.readFile(tmpl.src, 'utf-8')
let compiledSrc
try {
compiledSrc = lodashTemplate(srcContents, {})(tmpl.data)
} catch (err) {
console.error('Error compiling template: ', tmpl)
throw err
}
const dest = join(destDir, tmpl.path)
// consola.log('Compile template', dest)
await fsExtra.mkdirp(dirname(dest))
await fsExtra.writeFile(dest, compiledSrc)

View File

@ -1,3 +1,4 @@
// @ts-nocheck
import fs from 'fs'
import path from 'path'
import consola from 'consola'
@ -5,10 +6,9 @@ import defaults from 'lodash/defaults'
import merge from 'lodash/merge'
import cloneDeep from 'lodash/cloneDeep'
import createResolver from 'postcss-import-resolver'
import { Nuxt, tryRequireModule } from '@nuxt/kit'
import { isPureObject } from '@nuxt/kit'
import type { Nuxt } from '../../../core'
import type { NormalizedConfiguration } from '../../../config'
const isPureObject = obj => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
export const orderPresets = {
cssnanoLast (names) {
@ -30,17 +30,18 @@ export const orderPresets = {
}
}
let _postcssConfigFileWarningShown
function postcssConfigFileWarning () {
if (postcssConfigFileWarning.executed) {
if (_postcssConfigFileWarningShown) {
return
}
consola.warn('Please use `build.postcss` in your nuxt.config.js instead of an external config file. Support for such files will be removed in Nuxt 3 as they remove all defaults set by Nuxt and can cause severe problems with features like alias resolving inside your CSS.')
postcssConfigFileWarning.executed = true
_postcssConfigFileWarningShown = true
}
export default class PostcssConfig {
nuxt: Nuxt
options: NormalizedConfiguration
options: Nuxt['options']
constructor (nuxt) {
this.nuxt = nuxt
@ -150,7 +151,7 @@ export default class PostcssConfig {
// Map postcss plugins into instances on object mode once
config.plugins = this.sortPlugins(config)
.map((p) => {
const plugin = this.nuxt.resolver.requireModule(p)
const plugin = tryRequireModule(p)
const opts = plugins[p]
if (opts === false) {
return false // Disabled

View File

@ -1,3 +1,5 @@
export default {
import { defineNuxtConfig } from '@nuxt/kit'
export default defineNuxtConfig({
vite: true
}
})

View File

@ -1,7 +1,7 @@
import { promisify } from 'util'
import { resolve, relative, dirname } from 'path'
import Module from 'module'
import { writeFile, mkdir } from 'fs/promises'
import { writeFile, mkdir, unlink, symlink } from 'fs/promises'
import chalk from 'chalk'
import consola from 'consola'
import rimraf from 'rimraf'
@ -12,12 +12,16 @@ import alias from '@rollup/plugin-alias'
import esbuild from 'rollup-plugin-esbuild'
import { mkdist } from 'mkdist'
import prettyBytes from 'pretty-bytes'
import execa from 'execa'
import dts from 'rollup-plugin-dts'
interface BuildEntry {
name: string
input: string
output: string
bundle: boolean
srcDir: string
distDir: string
format: 'esm' | 'cjs'
}
@ -51,7 +55,14 @@ async function main () {
ctx.externals.push(...buildOptions.externals)
}
await promisify(rimraf)(resolve(ctx.rootDir, 'dist'))
const distDir = resolve(ctx.rootDir, 'dist')
await unlink(distDir).catch(() => {})
await promisify(rimraf)(distDir)
if (buildOptions.prebuild) {
const [cmd, ...args] = buildOptions.prebuild.split(' ')
await execa(cmd, args)
}
if (args.includes('--stub')) {
const stubbed: string[] = []
@ -65,42 +76,52 @@ async function main () {
const esStub = `export * from '${input}'`
await writeFile(output, entry.format === 'cjs' ? cjsStub : esStub)
await writeFile(output.replace('.js', '.d.ts'), esStub)
} else {
const outDir = resolve(ctx.rootDir, entry.output)
const srcDir = resolve(ctx.rootDir, entry.input)
await unlink(outDir).catch(() => { })
await symlink(srcDir, outDir)
}
}
consola.success(`Stub done: ${stubbed.join(', ')}`)
return
}
consola.info(chalk.cyan(`Builduing ${pkg.name}`))
if (process.env.DEBUG) {
consola.info(`${chalk.cyan(`Builduing ${pkg.name}`)}
${chalk.bold('Root dir:')} ${ctx.rootDir}
${chalk.bold('Entries:')}
${ctx.entries.map(entry => ' ' + dumpObject(entry)).join('\n')}
consola.info(`
${chalk.bold('Root dir:')} ${ctx.rootDir}
${chalk.bold('Entries:')}
${ctx.entries.map(entry => ' ' + dumpObject(entry)).join('\n')}
`)
}
const rollupOptions = getRollupOptions(ctx)
const buildEntries: { path: string, bytes?: number, exports?: string[], chunks?: string[] }[] = []
const usedImports = new Set<string>()
if (rollupOptions) {
const buildResult = await rollup(rollupOptions)
const outputOptions = rollupOptions.output as OutputOptions
const { output } = await buildResult.write(outputOptions)
const usedImports = new Set<string>()
const buildEntries: { path: string, bytes?: number, exports?: string[], chunks?: string[] }[] = []
for (const entry of output.filter(e => e.type === 'chunk') as OutputChunk[]) {
for (const id of entry.imports) {
usedImports.add(id)
}
if (entry.isEntry) {
buildEntries.push({
path: entry.fileName,
path: relative(ctx.rootDir, resolve(outputOptions.dir, entry.fileName)),
bytes: entry.code.length * 4,
exports: entry.exports
})
}
}
// Types
rollupOptions.plugins.push(dts())
const typesBuild = await rollup(rollupOptions)
await typesBuild.write(outputOptions)
}
for (const entry of ctx.entries.filter(e => !e.bundle)) {
const { writtenFiles } = await mkdist({
rootDir: ctx.rootDir,
@ -109,23 +130,21 @@ ${ctx.entries.map(entry => ' ' + dumpObject(entry)).join('\n')}
format: entry.format
})
buildEntries.push({
path: entry.output,
bytes: 0,
chunks: writtenFiles.map(p => relative(resolve(ctx.rootDir, entry.output), p))
path: relative(ctx.rootDir, entry.output),
chunks: [`${writtenFiles.length} files`]
})
}
consola.success(chalk.green('Build succeed'))
if (process.env.DEBUG) {
consola.log(`
${buildEntries.map(entry => `${chalk.bold(entry.path)}
size: ${chalk.cyan(entry.bytes ? prettyBytes(entry.bytes) : '-')}
exports: ${chalk.gray(entry.exports ? entry.exports.join(', ') : '-')}
chunks: ${chalk.gray(entry.chunks ? entry.chunks.join(', ') : '-')}`
).join('\n')}`)
consola.success(chalk.green('Build succeed for ' + pkg.name))
for (const entry of buildEntries) {
consola.log(` ${chalk.bold(entry.path)} (` + [
entry.bytes && `size: ${chalk.cyan(prettyBytes(entry.bytes))}`,
entry.exports && `exports: ${chalk.gray(entry.exports.join(', '))}`,
entry.chunks && `chunks: ${chalk.gray(entry.chunks.join(', '))}`
].filter(Boolean).join(', ') + ')')
}
if (rollupOptions) {
const usedDependencies = new Set<string>()
const unusedDependencies = new Set<string>(Object.keys(pkg.dependencies || {}))
const implicitDependnecies = new Set<string>()
@ -153,6 +172,9 @@ ${buildEntries.map(entry => `${chalk.bold(entry.path)}
if (implicitDependnecies.size) {
consola.warn('Potential implicit dependencies found:', Array.from(implicitDependnecies).map(id => chalk.cyan(id)).join(', '))
}
}
consola.log('')
}
function resolveEntry (input: string | [string, Partial<BuildEntry>] | Partial<BuildEntry>): BuildEntry {
@ -163,9 +185,9 @@ function resolveEntry (input: string | [string, Partial<BuildEntry>] | Partial<B
if (Array.isArray(input)) {
entry = { name: input[0], ...input[1] }
}
entry.input = entry.input ?? `src/${entry.name}`
entry.output = entry.output ?? `dist/${entry.name}`
entry.bundle = entry.bundle ?? !entry.input.endsWith('/')
entry.input = entry.input ?? resolve(entry.srcDir || 'src', './' + entry.name)
entry.output = entry.output ?? resolve(entry.distDir || 'dist', './' + entry.name)
entry.bundle = entry.bundle ?? !(entry.input.endsWith('/') || entry.name.endsWith('/'))
entry.format = entry.format ?? 'esm'
return entry as BuildEntry
}
@ -174,13 +196,18 @@ function dumpObject (obj) {
return '{ ' + Object.keys(obj).map(key => `${key}: ${JSON.stringify(obj[key])}`).join(', ') + ' }'
}
function getRollupOptions (ctx: BuildContext): RollupOptions {
function getRollupOptions (ctx: BuildContext): RollupOptions | null {
const extensions = ['.ts', '.mjs', '.js', '.json']
const r = (...path) => resolve(ctx.rootDir, ...path)
const entries = ctx.entries.filter(e => e.bundle)
if (!entries.length) {
return null
}
return <RollupOptions>{
input: ctx.entries.filter(e => e.bundle).map(e => e.input),
input: entries.map(e => e.input),
output: {
dir: r('dist'),
@ -194,7 +221,17 @@ function getRollupOptions (ctx: BuildContext): RollupOptions {
if (id[0] === '.' || id[0] === '/' || id.includes('src/')) {
return false
}
return !!ctx.externals.find(ext => id.includes(ext))
const isExplicitExternal = !!ctx.externals.find(ext => id.includes(ext))
if (!isExplicitExternal) {
consola.warn(`Inlining external ${id}`)
}
return isExplicitExternal
},
onwarn (warning, rollupWarn) {
if (!['CIRCULAR_DEPENDENCY'].includes(warning.code)) {
rollupWarn(warning)
}
},
plugins: [
@ -222,4 +259,7 @@ function getRollupOptions (ctx: BuildContext): RollupOptions {
}
}
main().catch(consola.error)
main().catch((err) => {
consola.error(err)
process.exit(1)
})

View File

@ -2196,6 +2196,17 @@
"@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
camelcase "^5.0.0"
"@vue/compiler-core@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.10.tgz#ced92120c6b9bab7b6c44dfe5e3e5cf2ea422531"
integrity sha512-rayD+aODgX9CWgWv0cAI+whPLyMmtkWfNGsZpdpsaIloh8mY2hX8+SvE1Nn3755YhGWJ/7oaDEcNpOctGwZbsA==
dependencies:
"@babel/parser" "^7.12.0"
"@babel/types" "^7.12.0"
"@vue/shared" "3.0.10"
estree-walker "^2.0.1"
source-map "^0.6.1"
"@vue/compiler-core@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.9.tgz#ec7efa676889aee006fc43739ee4a67a952ac623"
@ -2207,6 +2218,14 @@
estree-walker "^2.0.1"
source-map "^0.6.1"
"@vue/compiler-dom@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.10.tgz#59d3597498e7d4b0b92f3886a823f99d5b08f1fe"
integrity sha512-SzN1li9xAxtqkZimR1AFU2t1N0vzsAJxR/5764xoS0xedwhUU9s8s+Tks2FNMLsXiqdkP2Qd4zAM+9EwTbZmRw==
dependencies:
"@vue/compiler-core" "3.0.10"
"@vue/shared" "3.0.10"
"@vue/compiler-dom@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.9.tgz#1fd554097d9ab36eca73bc6d0d9607fecf94e71c"
@ -2245,6 +2264,13 @@
"@vue/compiler-dom" "3.0.9"
"@vue/shared" "3.0.9"
"@vue/reactivity@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.10.tgz#012830733291e60827f3b228d425ad53b83484ce"
integrity sha512-0GOSqlIv/a5wy4r6fAcdaglQ8v2sLYMRUpu49yK8Z2vHccK85Ym3R9C9K3vo6dfBRGbbCVvoKxYtQw49LvE8Ug==
dependencies:
"@vue/shared" "3.0.10"
"@vue/reactivity@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.9.tgz#875f241b8c10262560b190ccdeff2d0ab7053e11"
@ -2252,6 +2278,14 @@
dependencies:
"@vue/shared" "3.0.9"
"@vue/runtime-core@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.10.tgz#cb8730c0ec86ea5c1cfa701facc0a97bf59b15a2"
integrity sha512-qKhCOwHGff5YEdyClO1gf9Q9xgaPPz/qJ2GyzNZkPb00WcXJ3l+yTgHZWaSywRLs9GD1y9Ff3C0MIowzj95NHA==
dependencies:
"@vue/reactivity" "3.0.10"
"@vue/shared" "3.0.10"
"@vue/runtime-core@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.9.tgz#9665f149468355a524a304cb8f260147a4d294e6"
@ -2260,6 +2294,15 @@
"@vue/reactivity" "3.0.9"
"@vue/shared" "3.0.9"
"@vue/runtime-dom@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.10.tgz#80c6ee28caeabf74f31357d2c64d177945bd8a5f"
integrity sha512-8yRAALc/884UlYWY7hJImecvow1Cngbl2B6n0ThYTms08FVQ3W9tdW0MEvR3JVit06JyQLS1Qvwdn1PwNPPDqg==
dependencies:
"@vue/runtime-core" "3.0.10"
"@vue/shared" "3.0.10"
csstype "^2.6.8"
"@vue/runtime-dom@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.9.tgz#16a1d001dc746a9f346ee7fb9de90d52ad097b61"
@ -2277,6 +2320,11 @@
"@vue/compiler-ssr" "3.0.9"
"@vue/shared" "3.0.9"
"@vue/shared@3.0.10":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.10.tgz#5476d5615d01bf339c65c2e804f5909bbc27844a"
integrity sha512-p8GJ+bGpEGiEHICwcCH/EtJnkZQllrOfm1J2J+Ep0ydMte25bPnArgrY/h2Tn1LKqqR3LXyQlOSYY6gJgiW2LQ==
"@vue/shared@3.0.9":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.9.tgz#09882d745ded52b07e4481d036659d733edd2a9a"
@ -7544,10 +7592,10 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
mkdist@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/mkdist/-/mkdist-0.1.2.tgz#7365d975005976a7ac22540c0e76f8b21b33cdb0"
integrity sha512-NELp7Nnz8pKek6pvIz4snM1j+D8ni9Gm5UhKApuK9pgrbd/Q3KveVg2HtEWy73AKuG1wXnK9O3cjfKD5OgG9Ww==
mkdist@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/mkdist/-/mkdist-0.1.3.tgz#46787c2493493d8eff1770700da23d5c4fc3d844"
integrity sha512-WQ0l+v0ICvxvsmgi2MtePzeyis5kMDRUMnibUDsc1NdVSo+lsoiIYbLrvIBgKJGJ2ITMaLDtCAHiFjF3U7h29A==
dependencies:
defu "^3.2.2"
esbuild "^0.8.56"
@ -9970,13 +10018,6 @@ static-extend@^0.1.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
std-env@3.0.0-alpha:
version "3.0.0-alpha"
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.0.0-alpha.tgz#f161964da20a8af6a11bdbccfd39a99b5d7728d1"
integrity sha512-WWaDtGMLaG1AqB8n792lM8zfR38xVw8iFIFGBvQRV4L+4kps54gvluqKcOq2Do2FwXNoKKjUJHRL1xgnz2pN3A==
dependencies:
ci-info "^2.0.0"
std-env@^2.2.1, std-env@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.3.0.tgz#66d4a4a4d5224242ed8e43f5d65cfa9095216eee"
@ -10634,6 +10675,11 @@ unbox-primitive@^1.0.0:
has-symbols "^1.0.0"
which-boxed-primitive "^1.0.1"
unctx@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/unctx/-/unctx-0.0.3.tgz#e06f67d5bebe2babe5a57c1dc13d77255e3458c0"
integrity sha512-x+NCoXiYn93laQNnoJGZx2UZj7vv8ViFKadUCDx9S4QoPIkGRCYT0OLUDEMlg/B+Q6bnqdSkPLmiy/kjNIwVyQ==
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
@ -10904,6 +10950,15 @@ vue-template-compiler@^2.6.12:
de-indent "^1.0.2"
he "^1.1.0"
vue@^3.0.10:
version "3.0.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.10.tgz#b5d2801c6ac0e756c850ad7a8f9a78cbccbad02a"
integrity sha512-6arZ722uqIArSNUU94aqx0Pq0IMHFqYZuJ+U+q9HGdZZu11VFpyFP/L/hakijGFKp56Jr0yxJdWbDiJGWPxwww==
dependencies:
"@vue/compiler-dom" "3.0.10"
"@vue/runtime-dom" "3.0.10"
"@vue/shared" "3.0.10"
vue@^3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.9.tgz#c68ffc0e4aa2b0f1905124a9037b6e352de469ad"