diff --git a/package.json b/package.json
index 76cdf5abde..b111a14b02 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,8 @@
"scripts": {
"link": "lerna link",
"nuxt": "jiti ./scripts/nuxt",
- "build": "yarn workspaces run build",
- "stub": "yarn workspaces run stub",
+ "build": "yarn workspaces run build --silent",
+ "stub": "yarn workspaces run stub --silent",
"play": "yarn nuxt dev playground",
"lint": "eslint --ext .vue,.ts,.js .",
"test": "yarn lint",
diff --git a/packages/kit/package.json b/packages/kit/package.json
new file mode 100644
index 0000000000..6dcc1406b1
--- /dev/null
+++ b/packages/kit/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@nuxt/kit",
+ "version": "0.0.0",
+ "repository": "nuxt/framework",
+ "license": "MIT",
+ "main": "./dist/index.js",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "build": "jiti ../../scripts/build .",
+ "genconfig": "jiti ./scripts/genconfig",
+ "stub": "yarn build --stub",
+ "prepublishOnly": "yarn build && yarn genconfig"
+ },
+ "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"
+ },
+ "build": {
+ "entries": {
+ "index": {}
+ }
+ }
+}
diff --git a/packages/kit/scripts/genconfig.ts b/packages/kit/scripts/genconfig.ts
new file mode 100644
index 0000000000..63d96caf25
--- /dev/null
+++ b/packages/kit/scripts/genconfig.ts
@@ -0,0 +1,19 @@
+import { resolve } from 'path'
+import { mkdir, writeFile } from 'fs/promises'
+import { resolveSchema, generateTypes, generateMarkdown } from 'untyped'
+
+async function main () {
+ const genDir = resolve(__dirname, '../dist/config')
+ const srcConfig = await import('../src/config/schema').then(r => r.default)
+
+ const defaults = { rootDir: '/
/' }
+ const schema = resolveSchema(srcConfig, defaults)
+
+ 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'))
+}
+
+main().catch(console.error)
diff --git a/packages/kit/src/config/env.ts b/packages/kit/src/config/env.ts
new file mode 100644
index 0000000000..5d278a1c90
--- /dev/null
+++ b/packages/kit/src/config/env.ts
@@ -0,0 +1,97 @@
+import { resolve } from 'path'
+import { existsSync, promises as fsp } from 'fs'
+import dotenv from 'dotenv'
+
+export interface LoadDotEnvOptions {
+ rootDir: string
+ dotenvFile: string
+ expand: boolean
+ env: typeof process.env
+}
+
+export async function loadEnv (rootDir) {
+ // Load env
+ const env = await loalDotenv({
+ rootDir,
+ dotenvFile: '.env',
+ env: process.env,
+ expand: true
+ })
+
+ // Fill process.env so it is accessible in nuxt.config
+ for (const key in env) {
+ if (!key.startsWith('_') && process.env[key] === undefined) {
+ process.env[key] = env[key]
+ }
+ }
+}
+
+export async function loalDotenv (opts: LoadDotEnvOptions) {
+ const env = Object.create(null)
+
+ const dotenvFile = resolve(opts.rootDir, opts.dotenvFile)
+
+ if (await existsSync(dotenvFile)) {
+ const parsed = dotenv.parse(await fsp.readFile(dotenvFile, 'utf-8'))
+ Object.assign(env, parsed)
+ }
+
+ // Apply process.env
+ if (!opts.env._applied) {
+ Object.assign(env, opts.env)
+ env._applied = true
+ }
+
+ // Interpolate env
+ if (opts.expand) {
+ expand(env)
+ }
+
+ return env
+}
+
+// Based on https://github.com/motdotla/dotenv-expand
+function expand (target, source = {}, parse = v => v) {
+ function getValue (key) {
+ // Source value 'wins' over target value
+ return source[key] !== undefined ? source[key] : target[key]
+ }
+
+ function interpolate (value, parents = []) {
+ if (typeof value !== 'string') {
+ return value
+ }
+ const matches = value.match(/(.?\${?(?:[a-zA-Z0-9_:]+)?}?)/g) || []
+ return parse(matches.reduce((newValue, match) => {
+ const parts = /(.?)\${?([a-zA-Z0-9_:]+)?}?/g.exec(match)
+ const prefix = parts[1]
+
+ let value, replacePart
+
+ if (prefix === '\\') {
+ replacePart = parts[0]
+ value = replacePart.replace('\\$', '$')
+ } else {
+ const key = parts[2]
+ replacePart = parts[0].substring(prefix.length)
+
+ // Avoid recursion
+ if (parents.includes(key)) {
+ console.warn(`Please avoid recursive environment variables ( loop: ${parents.join(' > ')} > ${key} )`)
+ return ''
+ }
+
+ value = getValue(key)
+
+ // Resolve recursive interpolations
+ value = interpolate(value, [...parents, key])
+ }
+
+ return value !== undefined ? newValue.replace(replacePart, value) : newValue
+ }, value))
+ }
+
+ for (const key in target) {
+ target[key] = interpolate(getValue(key))
+ }
+}
diff --git a/packages/kit/src/config/load.ts b/packages/kit/src/config/load.ts
new file mode 100644
index 0000000000..d605a5c029
--- /dev/null
+++ b/packages/kit/src/config/load.ts
@@ -0,0 +1,57 @@
+import { resolve } from 'path'
+import defu from 'defu'
+import jiti from 'jiti'
+import { applyDefaults } from 'untyped'
+import * as rc from 'rc9'
+import nuxtConfigSchema from './schema'
+
+export interface LoadNuxtConfigOptions {
+ rootDir?: string
+ configFile?: string
+ config?: any
+}
+
+export function loadNuxtConfig (opts: LoadNuxtConfigOptions) {
+ const rootDir = resolve(process.cwd(), opts.rootDir || '.')
+
+ const _require = jiti(rootDir)
+
+ let configFile
+ try {
+ configFile = _require.resolve(resolve(rootDir, opts.configFile || 'nuxt.config'))
+ } catch (e) {
+ if (e.code !== 'MODULE_NOT_FOUND') {
+ throw (e)
+ }
+ // Skip if cannot resolve
+ configFile = undefined
+ }
+
+ let nuxtConfig: any = {}
+
+ if (configFile) {
+ // clearRequireCache(configFile) TODO
+ nuxtConfig = _require(configFile) || {}
+ if (nuxtConfig.default) {
+ nuxtConfig = nuxtConfig.default
+ }
+ nuxtConfig = { ...nuxtConfig }
+ }
+
+ // Combine configs
+ // Priority: configOverrides > nuxtConfig > .nuxtrc > .nuxtrc (global)
+ nuxtConfig = defu(
+ opts.config,
+ nuxtConfig,
+ rc.read({ name: '.nuxtrc', dir: rootDir }),
+ rc.readUser('.nuxtrc')
+ )
+
+ // Set rootDir
+ if (!nuxtConfig.rootDir) {
+ nuxtConfig.rootDir = rootDir
+ }
+
+ // Resolve and apply defaults
+ return applyDefaults(nuxtConfigSchema, nuxtConfig)
+}
diff --git a/packages/kit/src/config/schema/_app.ts b/packages/kit/src/config/schema/_app.ts
new file mode 100644
index 0000000000..3a2394302b
--- /dev/null
+++ b/packages/kit/src/config/schema/_app.ts
@@ -0,0 +1,141 @@
+import { resolve, join } from 'path'
+import { existsSync, readdirSync } from 'fs'
+import defu from 'defu'
+import { isRelative, joinURL, hasProtocol } from 'ufo'
+
+export default {
+ /**
+ * Vue.js configuration
+ */
+ vue: {
+ config: {
+ silent: { $resolve: (val, get) => val ?? get('dev') },
+ performance: { $resolve: (val, get) => val ?? get('dev') }
+ }
+ },
+
+ app: {
+ $resolve: (val, get) => {
+ const useCDN = hasProtocol(get('build.publicPath'), true) && !get('dev')
+ const isRelativePublicPath = isRelative(get('build.publicPath'))
+ return defu(val, {
+ basePath: get('router.base'),
+ assetsPath: isRelativePublicPath ? get('build.publicPath') : useCDN ? '/' : joinURL(get('router.base'), get('build.publicPath')),
+ cdnURL: useCDN ? get('build.publicPath') : null
+ })
+ }
+ },
+
+ /**
+ * Uses {srcDir}/app.html if exists by default otherwise nuxt default
+ */
+ appTemplatePath: {
+ $resolve: (val, get) => {
+ if (val) {
+ return resolve(get('srcDir'), val)
+ }
+ if (existsSync(join(get('srcDir'), 'app.html'))) {
+ return join(get('srcDir'), 'app.html')
+ }
+ return resolve(get('buildDir'), 'views/app.template.html')
+ }
+ },
+
+ store: {
+ $resolve: (val, get) => val !== false &&
+ existsSync(join(get('srcDir'), get('dir.store'))) &&
+ readdirSync(join(get('srcDir'), get('dir.store')))
+ .find(filename => filename !== 'README.md' && filename[0] !== '.')
+ },
+
+ /**
+ * debug errorss
+ */
+ debug: {
+ $resolve: (val, get) => val ?? get('dev')
+ },
+
+ vueMeta: null,
+
+ head: {
+ meta: [],
+ link: [],
+ style: [],
+ script: []
+ },
+
+ fetch: {
+ server: true,
+ client: true
+ },
+
+ plugins: [],
+
+ extendPlugins: null,
+
+ css: [],
+
+ layouts: {},
+
+ ErrorPage: null,
+
+ loading: {
+ color: 'black',
+ failedColor: 'red',
+ height: '2px',
+ throttle: 200,
+ duration: 5000,
+ continuous: false,
+ rtl: false,
+ css: true
+ },
+
+ loadingIndicator: {
+ $resolve: (val, get) => {
+ if (typeof val === 'string') {
+ val = { name: val }
+ }
+ return {
+ name: 'default',
+ color: get('loading.color') || '#D3D3D3',
+ color2: '#F5F5F5',
+ background: (get('manifest') && get('manifest.theme_color')) || 'white',
+ dev: get('dev'),
+ loading: get('messages.loading'),
+ ...val
+ }
+ }
+ },
+
+ pageTransition: {
+ $resolve: val => typeof val === 'string' ? { name: val } : val,
+ name: 'page',
+ mode: 'out-in',
+ appear: { $resolve: (val, get) => (get('render.ssr') === false) ? true : Boolean(val) },
+ appearClass: 'appear',
+ appearActiveClass: 'appear-active',
+ appearToClass: 'appear-to'
+ },
+
+ layoutTransition: {
+ $resolve: val => typeof val === 'string' ? { name: val } : val,
+ name: 'layout',
+ mode: 'out-in'
+ },
+
+ features: {
+ store: true,
+ layouts: true,
+ meta: true,
+ middleware: true,
+ transitions: true,
+ deprecations: true,
+ validate: true,
+ asyncData: true,
+ fetch: true,
+ clientOnline: true,
+ clientPrefetch: true,
+ componentAliases: true,
+ componentClientOnly: true
+ }
+}
diff --git a/packages/kit/src/config/schema/_common.ts b/packages/kit/src/config/schema/_common.ts
new file mode 100644
index 0000000000..4ad783514f
--- /dev/null
+++ b/packages/kit/src/config/schema/_common.ts
@@ -0,0 +1,166 @@
+import { join, resolve } from 'path'
+import env from 'std-env'
+import createRequire from 'create-require'
+import { pascalCase } from 'scule'
+import jiti from 'jiti'
+
+export default {
+ rootDir: {
+ $resolve: val => typeof val === 'string' ? resolve(val) : process.cwd()
+ },
+
+ srcDir: {
+ $resolve: (val, get) => resolve(get('rootDir'), val || '.')
+ },
+
+ buildDir: {
+ $resolve: (val, get) => resolve(get('rootDir'), val || '.nuxt')
+ },
+
+ dev: Boolean(env.dev),
+ test: Boolean(env.test),
+ debug: undefined,
+ env: {
+ $resolve: (val) => {
+ val = { ...val }
+ for (const key in process.env) {
+ if (key.startsWith('NUXT_ENV_')) {
+ val[key] = process.env[key]
+ }
+ }
+ return val
+ }
+ },
+
+ createRequire: {
+ $resolve: (val: any) => {
+ val = process.env.NUXT_CREATE_REQUIRE || val ||
+ (typeof jest !== 'undefined' ? 'native' : 'jiti')
+ if (val === 'jiti') {
+ return p => jiti(typeof p === 'string' ? p : p.filename)
+ }
+ if (val === 'native') {
+ return p => createRequire(typeof p === 'string' ? p : p.filename)
+ }
+ return val
+ }
+ },
+
+ target: {
+ $resolve: val => ['server', 'static'].includes(val) ? val : 'server'
+ },
+
+ ssr: true,
+
+ mode: {
+ $resolve: (val, get) => val || (get('ssr') ? 'spa' : 'universal'),
+ $schema: { deprecated: '`mode` option is deprecated' }
+ },
+
+ modern: undefined,
+
+ modules: [],
+ buildModules: [],
+ _modules: [],
+
+ globalName: {
+ $resolve: val => (typeof val === 'string' && /^[a-zA-Z]+$/.test(val)) ? val.toLocaleLowerCase() : 'nuxt'
+ },
+
+ globals: {
+ id: globalName => `__${globalName}`,
+ nuxt: globalName => `$${globalName}`,
+ context: globalName => `__${globalName.toUpperCase()}__`,
+ pluginPrefix: globalName => globalName,
+ readyCallback: globalName => `on${pascalCase(globalName)}Ready`,
+ loadedCallback: globalName => `_on${pascalCase(globalName)}Loaded`
+ },
+
+ serverMiddleware: {
+ $resolve: (val: any) => {
+ if (!val) {
+ return []
+ }
+ if (!Array.isArray(val)) {
+ return Object.entries(val).map(([path, handler]) => ({ path, handler }))
+ }
+ return val
+ }
+ },
+
+ _nuxtConfigFile: {
+ $resolve: (val, get) => resolve(get('rootDir'), val || 'nuxt.config.js')
+ },
+
+ _nuxtConfigFiles: {
+ $resolve: (val, get) => [].concat(get('_nuxtConfigFile'), val).filter(Boolean)
+ },
+
+ modulesDir: {
+ $default: ['node_modules'],
+ $resolve: (val, get) => val.map(dir => resolve(get('rootDir'), dir))
+ },
+
+ dir: {
+ assets: 'assets',
+ app: 'app',
+ layouts: 'layouts',
+ middleware: 'middleware',
+ pages: 'pages',
+ static: 'static',
+ store: 'store'
+ },
+
+ extensions: {
+ $resolve: val => ['js', 'mjs', 'ts', 'tsx', 'vue'].concat(val).filter(Boolean)
+ },
+
+ styleExtensions: ['css', 'pcss', 'postcss', 'styl', 'stylus', 'scss', 'sass', 'less'],
+
+ alias: {
+ $resolve: (val, get) => ({
+ '~~': get('rootDir'),
+ '@@': get('rootDir'),
+ '~': get('srcDir'),
+ '@': get('srcDir'),
+ [get('dir.assets')]: join(get('srcDir'), get('dir.assets')),
+ [get('dir.static')]: join(get('srcDir', get('dir.static'))),
+ ...val
+ })
+ },
+
+ ignoreOptions: undefined,
+ ignorePrefix: '-',
+ ignore: {
+ $resolve: (val, get) => [
+ '**/*.test.*',
+ '**/*.spec.*',
+ get('ignorePrefix') && `**/${get('ignorePrefix')}*.*`
+ ].concat(val).filter(Boolean)
+ },
+
+ watch: {
+ $resolve: (_val, get) => [].concat(get._nuxtConfigFiles).filter(Boolean)
+ },
+
+ watchers: {
+ rewatchOnRawEvents: undefined,
+ webpack: {
+ aggregateTimeout: 1000
+ },
+ chokidar: {
+ ignoreInitial: true
+ }
+ },
+
+ editor: undefined,
+
+ hooks: null,
+
+ privateRuntimeConfig: {},
+ publicRuntimeConfig: {
+ app: {
+ $resolve: (val, get) => ({ ...get('app'), ...(val || {}) })
+ }
+ }
+}
diff --git a/packages/kit/src/config/schema/build.ts b/packages/kit/src/config/schema/build.ts
new file mode 100644
index 0000000000..1f069dd3e9
--- /dev/null
+++ b/packages/kit/src/config/schema/build.ts
@@ -0,0 +1,159 @@
+import env from 'std-env'
+import { hasProtocol } from 'ufo'
+
+export default {
+ quiet: Boolean(env.ci || env.test),
+ analyze: false,
+ profile: process.argv.includes('--profile'),
+ extractCSS: false,
+ cssSourceMap: {
+ $resolve: (val, get) => val ?? get('dev')
+ },
+ ssr: undefined,
+ parallel: {
+ $resolve: (val, get) => get('build.extractCSS') ? false : Boolean(val)
+ },
+ cache: false,
+ standalone: false,
+ publicPath: {
+ $resolve: (val, get) => {
+ if (hasProtocol(val, true) && get('dev')) { val = null }
+ return (val || '/_nuxt/').replace(/([^/])$/, '$1/')
+ }
+ },
+ serverURLPolyfill: 'url',
+ filenames: {
+ app: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`,
+ chunk: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`,
+ css: ({ isDev }) => isDev ? '[name].css' : 'css/[contenthash:7].css',
+ img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
+ font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
+ video: ({ isDev }) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
+ },
+ loaders: {
+ // $resolve: (val, get) => {
+ // const styleLoaders = [
+ // 'css', 'cssModules', 'less',
+ // 'sass', 'scss', 'stylus', 'vueStyle'
+ // ]
+ // for (const name of styleLoaders) {
+ // const loader = val[name]
+ // if (loader && loader.sourceMap === undefined) {
+ // loader.sourceMap = Boolean(get('build.cssSourceMap'))
+ // }
+ // }
+ // },
+ file: { esModule: false },
+ fontUrl: { esModule: false, limit: 1000 },
+ imgUrl: { esModule: false, limit: 1000 },
+ pugPlain: {},
+ vue: {
+ productionMode: { $resolve: (val, get) => val ?? get('dev') },
+ transformAssetUrls: {
+ video: 'src',
+ source: 'src',
+ object: 'src',
+ embed: 'src'
+ }
+ },
+ css: { esModule: false },
+ cssModules: {
+ esModule: false,
+ modules: {
+ localIdentName: '[local]_[hash:base64:5]'
+ }
+ },
+ less: {},
+ sass: {
+ sassOptions: {
+ indentedSyntax: true
+ }
+ },
+ scss: {},
+ stylus: {},
+ vueStyle: {}
+ },
+ styleResources: {},
+ plugins: [],
+ terser: {},
+ hardSource: false,
+ aggressiveCodeRemoval: false,
+ optimizeCSS: {
+ $resolve: (val, get) => val ?? (get('build.extractCSS') ? {} : false)
+ },
+ optimization: {
+ runtimeChunk: 'single',
+ minimize: { $resolve: (val, get) => val ?? get('dev') },
+ minimizer: undefined,
+ splitChunks: {
+ chunks: 'all',
+ automaticNameDelimiter: '/',
+ cacheGroups: {}
+ }
+ },
+ splitChunks: {
+ layouts: false,
+ pages: true,
+ commons: true
+ },
+ corejs: 'auto',
+ babel: {
+ configFile: false,
+ babelrc: false,
+ presets: {},
+ cacheDirectory: {
+ $resolve: (val, get) => val ?? get('dev')
+ }
+ },
+ transpile: {
+ $resolve: val => [].concat(val).filter(Boolean)
+ },
+ postcss: {
+ preset: {
+ // https://cssdb.org/#staging-process
+ stage: 2
+ }
+ },
+ html: {
+ minify: {
+ collapseBooleanAttributes: true,
+ decodeEntities: true,
+ minifyCSS: true,
+ minifyJS: true,
+ processConditionalComments: true,
+ removeEmptyAttributes: true,
+ removeRedundantAttributes: true,
+ trimCustomFragments: true,
+ useShortDoctype: true
+ }
+ },
+
+ template: undefined,
+ templates: [],
+
+ watch: [],
+ devMiddleware: {
+ stats: 'none'
+ },
+ hotMiddleware: {},
+
+ vendor: {
+ $meta: {
+ deprecated: 'vendor has been deprecated since nuxt 2'
+ }
+ },
+
+ stats: {
+ $resolve: (val, get) => (val === 'none' || get('build.quite')) ? false : val,
+ excludeAssets: [
+ /.map$/,
+ /index\..+\.html$/,
+ /vue-ssr-(client|modern)-manifest.json/
+ ]
+ },
+ friendlyErrors: true,
+ additionalExtensions: [],
+ warningIgnoreFilters: [],
+
+ followSymlinks: false
+}
diff --git a/packages/kit/src/config/schema/cli.ts b/packages/kit/src/config/schema/cli.ts
new file mode 100644
index 0000000000..0e79115bd1
--- /dev/null
+++ b/packages/kit/src/config/schema/cli.ts
@@ -0,0 +1,4 @@
+export default {
+ badgeMessages: [],
+ bannerColor: 'green'
+}
diff --git a/packages/kit/src/config/schema/generate.ts b/packages/kit/src/config/schema/generate.ts
new file mode 100644
index 0000000000..a9caa545ba
--- /dev/null
+++ b/packages/kit/src/config/schema/generate.ts
@@ -0,0 +1,29 @@
+import { resolve } from 'path'
+import { joinURL } from 'ufo'
+
+export default {
+ dir: {
+ $resolve: (val = 'dist', get) => resolve(get('rootDir'), val)
+ },
+ routes: [],
+ exclude: [],
+ concurrency: 500,
+ interval: 0,
+ subFolders: true,
+ fallback: { $resolve: val => val === true ? '400.html' : (val || '200.html') },
+ crawler: true,
+ manifest: true,
+ nojekyll: true,
+ cache: {
+ ignore: [],
+ globbyOptions: {
+ gitignore: true
+ }
+ },
+ staticAssets: {
+ dir: 'static',
+ base: { $resolve: (val, get) => val || joinURL(get('app.assetsPath'), get('generate.dir')) },
+ versionBase: { $resolve: (val, get) => val || joinURL(get('generate.base'), get('generate.version')) },
+ version: { $resolve: val => val || (String(Math.round(Date.now() / 1000))) }
+ }
+}
diff --git a/packages/kit/src/config/schema/index.ts b/packages/kit/src/config/schema/index.ts
new file mode 100644
index 0000000000..5e24730c3e
--- /dev/null
+++ b/packages/kit/src/config/schema/index.ts
@@ -0,0 +1,40 @@
+
+import _app from './_app'
+import _common from './_common'
+import build from './build'
+import messages from './messages'
+import render from './render'
+import router from './router'
+import server from './server'
+import cli from './cli'
+import generate from './generate'
+
+/*
+TODO for top level normalizations: (nuxt2)
+- transition => pageTransition
+- export => generate
+- gzip => compressor
+- Apply preset
+- render.etag.hash should be a function
+- deprecated devModules
+- set consola level to 0 if build.quite is true
+- Ad-hoc: loading-screen, components and telemtry
+- build.indicator and build.loadingScreen
+- build.crossorigin => render.crossorigin
+- render.csp.unsafeInlineCompatiblity => render.csp.unsafeInlineCompatibility
+- guards: rootDir:buildDir rootDir:generate.dir srcDir:buildDir srcDir:generate.dir
+- _publicPath (original value of publicPath)
+- options.build.babel.presets (array) warn @nuxtjs/babel-preset-app => @nuxt/babel-preset-app
+*/
+
+export default {
+ ..._app,
+ ..._common,
+ build,
+ messages,
+ render,
+ router,
+ server,
+ cli,
+ generate
+}
diff --git a/packages/kit/src/config/schema/messages.ts b/packages/kit/src/config/schema/messages.ts
new file mode 100644
index 0000000000..ad1ff51de1
--- /dev/null
+++ b/packages/kit/src/config/schema/messages.ts
@@ -0,0 +1,10 @@
+export default {
+ loading: 'Loading...',
+ error_404: 'This page could not be found',
+ server_error: 'Server error',
+ nuxtjs: 'Nuxt',
+ back_to_home: 'Back to the home page',
+ server_error_details: 'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
+ client_error: 'Error',
+ client_error_details: 'An error occurred while rendering the page. Check developer tools console for details.'
+}
diff --git a/packages/kit/src/config/schema/render.ts b/packages/kit/src/config/schema/render.ts
new file mode 100644
index 0000000000..2c09cfc65b
--- /dev/null
+++ b/packages/kit/src/config/schema/render.ts
@@ -0,0 +1,58 @@
+export default {
+ bundleRenderer: {
+ shouldPrefetch: () => false,
+ shouldPreload: (_fileWithoutQuery, asType) => ['script', 'style'].includes(asType),
+ /**
+ * enabled by default for development
+ */
+ runInNewContext: { $resolve: (val, get) => val ?? get('dev') }
+ },
+ crossorigin: undefined,
+ resourceHints: true,
+ ssr: undefined,
+ ssrLog: { $resolve: (val, get) => get('dev') ? Boolean(val) : false },
+ http2: {
+ push: false,
+ shouldPush: null,
+ pushAssets: null
+ },
+ static: {
+ prefix: true
+ },
+ compressor: {
+ threshold: 0
+ },
+ etag: {
+ hash: false,
+ weak: false
+ },
+ csp: {
+ $resolve: (val, get) => {
+ if (!val) { return false }
+ return {
+ hashAlgorithm: 'sha256',
+ allowedSources: undefined,
+ policies: undefined,
+ addMeta: Boolean(get('target') === 'static'),
+ unsafeInlineCompatibility: false,
+ reportOnly: get('debug'),
+ ...val
+ }
+ }
+ },
+ dist: {
+ index: false,
+ maxAge: '1y'
+ },
+ // https://github.com/nuxt/serve-placeholder
+ fallback: {
+ dist: {},
+ static: {
+ skipUnknown: true,
+ handlers: {
+ '.htm': false,
+ '.html': false
+ }
+ }
+ }
+}
diff --git a/packages/kit/src/config/schema/router.ts b/packages/kit/src/config/schema/router.ts
new file mode 100644
index 0000000000..2db41b6bbb
--- /dev/null
+++ b/packages/kit/src/config/schema/router.ts
@@ -0,0 +1,31 @@
+import { normalizeURL, withTrailingSlash } from 'ufo'
+
+export default {
+ mode: 'history',
+ base: {
+ $resolve: (val = '/') => withTrailingSlash(normalizeURL(val))
+ },
+ _routerBaseSpecified: {
+ $resolve: (_val, get) => typeof get('router.base') === 'string'
+ },
+ routes: [],
+ routeNameSplitter: '-',
+ middleware: {
+ $resolve: val => Array.isArray(val) ? val : [val].filter(Boolean)
+ },
+ linkActiveClass: 'nuxt-link-active',
+ linkExactActiveClass: 'nuxt-link-exact-active',
+ linkPrefetchedClass: false,
+ extendRoutes: null,
+ scrollBehavior: {
+ $schema: {
+ deprecated: 'router.scrollBehavior` property is deprecated in favor of using `~/app/router.scrollBehavior.js` file, learn more: https://nuxtjs.org/api/configuration-router#scrollbehavior'
+ }
+ },
+ parseQuery: false,
+ stringifyQuery: false,
+ fallback: false,
+ prefetchLinks: true,
+ prefetchPayloads: true,
+ trailingSlash: undefined
+}
diff --git a/packages/kit/src/config/schema/server.ts b/packages/kit/src/config/schema/server.ts
new file mode 100644
index 0000000000..a476ab909a
--- /dev/null
+++ b/packages/kit/src/config/schema/server.ts
@@ -0,0 +1,7 @@
+export default {
+ https: false,
+ port: process.env.NUXT_PORT || process.env.PORT || process.env.npm_package_config_nuxt_port || 3000,
+ host: process.env.NUXT_HOST || process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost',
+ socket: process.env.UNIX_SOCKET || process.env.npm_package_config_unix_socket,
+ timing: (val: any) => val ? ({ total: true, ...val }) : false
+}
diff --git a/packages/kit/src/index.ts b/packages/kit/src/index.ts
new file mode 100644
index 0000000000..95d535bbc5
--- /dev/null
+++ b/packages/kit/src/index.ts
@@ -0,0 +1,2 @@
+export * from './config/load'
+export * from './config/env'
diff --git a/packages/nuxt3/src/config/config/_app.ts b/packages/nuxt3/src/config/config/_app.ts
deleted file mode 100644
index 903ff8cf48..0000000000
--- a/packages/nuxt3/src/config/config/_app.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import type { App } from 'vue'
-import type { MetaInfo, VueMetaOptions } from 'vue-meta'
-
-type Plugin = string | { mode?: 'all' | 'client' | 'server', src: string, ssr?: boolean }
-
-interface AppOptions {
- css: string[]
- head: MetaInfo | (() => MetaInfo)
- ErrorPage: null | string
- extendPlugins: null | ((plugins: Plugin[]) => Plugin[])
- features: {
- store: boolean
- layouts: boolean
- meta: boolean
- middleware: boolean
- transitions: boolean
- deprecations: boolean
- validate: boolean
- asyncData: boolean
- fetch: boolean
- clientOnline: boolean
- clientPrefetch: boolean
- clientUseUrl: boolean
- componentAliases: boolean
- componentClientOnly: boolean
- }
- fetch: {
- server: boolean
- client: boolean
- }
- layouts: {}
- layoutTransition: {
- name: string
- mode?: string | 'out-in'
- }
- loading: string | false | {
- color?: string
- continuous?: boolean
- css?: boolean
- duration?: number
- failedColor?: string
- height?: string
- rtl?: boolean
- throttle?: number
- }
- loadingIndicator: string | false | {
- background?: string
- color?: string
- color2?: string
- name?: string
- }
- pageTransition: {
- name: string
- mode?: string | 'out-in'
- appear?: boolean
- appearClass?: string
- appearActiveClass?: string
- appearToClass?: string
- }
- plugins: Array
- vue: {
- config: Partial
- }
- vueMeta: null | VueMetaOptions
-}
-
-export default (): AppOptions => ({
- vue: {
- config: {
- performance: undefined // = dev
- }
- },
-
- vueMeta: null,
-
- head: {
- meta: [],
- link: [],
- style: [],
- script: []
- },
-
- fetch: {
- server: true,
- client: true
- },
-
- plugins: [],
-
- extendPlugins: null,
-
- css: [],
-
- layouts: {},
-
- ErrorPage: null,
-
- loading: {
- color: 'black',
- failedColor: 'red',
- height: '2px',
- throttle: 200,
- duration: 5000,
- continuous: false,
- rtl: false,
- css: true
- },
-
- loadingIndicator: 'default',
-
- pageTransition: {
- name: 'page',
- mode: 'out-in',
- appear: false,
- appearClass: 'appear',
- appearActiveClass: 'appear-active',
- appearToClass: 'appear-to'
- },
-
- layoutTransition: {
- name: 'layout',
- mode: 'out-in'
- },
-
- features: {
- store: true,
- layouts: true,
- meta: true,
- middleware: true,
- transitions: true,
- deprecations: true,
- validate: true,
- asyncData: true,
- fetch: true,
- clientOnline: true,
- clientPrefetch: true,
- clientUseUrl: false,
- componentAliases: true,
- componentClientOnly: true
- }
-})
-
-// type NormalizedConfiguration> = T & {
-// pageTransition?: Exclude
-// layoutTransition?: Exclude
-// extensions?: Exclude
-// }
-
-// export function normalizeAppConfig(options: O): asserts options is NormalizedConfiguration {
-// (options as NormalizedConfiguration).__normalized__ = true
-
-// // Normalize options
-// if (options.loading === true) {
-// delete options.loading
-// }
-
-// if (options.router && typeof options.router.base === 'string') {
-// (options as NormalizedConfiguration)._routerBaseSpecified = true
-// }
-
-// if (typeof options.pageTransition === 'string') {
-// options.pageTransition = { name: options.pageTransition }
-// }
-
-// if (typeof options.layoutTransition === 'string') {
-// options.layoutTransition = { name: options.layoutTransition }
-// }
-
-// if (typeof options.extensions === 'string') {
-// options.extensions = [options.extensions]
-// }
-// }
diff --git a/packages/nuxt3/src/config/config/_common.ts b/packages/nuxt3/src/config/config/_common.ts
deleted file mode 100644
index 1f861c7888..0000000000
--- a/packages/nuxt3/src/config/config/_common.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-import type { WatchOptions as ChokidarWatchOptions } from 'chokidar'
-import type express from 'express'
-import type { configHooksT } from 'hookable'
-import ignore from 'ignore'
-import capitalize from 'lodash/capitalize'
-import env from 'std-env'
-import type { Configuration as WebpackConfiguration } from 'webpack'
-import Hookable from 'hookable'
-import { TARGETS, MODES, Target, Mode } from '../../utils'
-
-import { APP_DIR } from '../../consts'
-import type { NormalizedConfiguration } from '../options'
-
-type IgnoreOptions = Parameters[0]
-type IgnoreInstance = ReturnType
-
-interface ExtendFunctionContext {
- isClient: boolean
- isDev: boolean
- isLegacy: boolean
- isModern: boolean
- isServer: boolean
- // TODO
- // loaders: NuxtOptionsLoaders
-}
-
-type ExtendFunction = (config: WebpackConfiguration, ctx: ExtendFunctionContext) => void
-
-interface NuxtHooks extends configHooksT {
-
- build?: {
- before?(builder: any, buildOptions: any): void
- compile?(params: { name: 'client' | 'server', compiler: any }): void
- compiled?(params: { name: 'client' | 'server', compiler: any, stats: any }): void
- done?(builder: any): void
- extendRoutes?(routes: any, resolve: any): void
- templates?(params: { templateFiles: any, templateVars: any, resolve: any }): void
- }
- close?(nuxt: any): void
- error?(error: Error): void
- generate?: {
- before?(generator: any, generateOptions: any): void
- distCopied?(generator: any): void
- distRemoved?(generator: any): void
- done?(generator: any): void
- extendRoutes?(routes: any): void
- page?(params: { route: any, path: any, html: any }): void
- routeCreated?(route: any, path: any, errors: any): void
- routeFailed?(route: any, errors: any): void
- }
- listen?(server: any, params: { host: string, port: number | string }): void
- modules?: {
- before?(moduleContainer: any, options: any): void
- done?(moduleContainer: any): void
- }
- ready?(nuxt: any): void
- render?: {
- before?(renderer: any, options: any): void
- done?(renderer: any): void
- errorMiddleware?(app: express.Application): void
- resourcesLoaded?(resources: any): void
- route?(url: string, result: any, context: any): void
- routeContext?(context: any): void
- routeDone?(url: string, result: any, context: any): void
- beforeResponse?(url: string, result: any, context: any): void
- setupMiddleware?(app: express.Application): void
- }
-}
-
-interface ModuleThis {
- extendBuild(fn: ExtendFunction): void
- options: NormalizedConfiguration
- nuxt: any // TBD
- [key: string]: any // TBD
-}
-
-export type ModuleHandler = (this: ModuleThis, moduleOptions: T) => Promise | void
-
-export type NuxtModule = string | ModuleHandler | [string | ModuleHandler, any]
-
-export type ServerMiddleware = string | { path: string, prefix?: boolean, handler: string | express.NextFunction } | express.NextFunction
-
-interface CommonConfiguration {
- _majorVersion: Number
- _modules: NuxtModule[]
- _nuxtConfigFile?: string
- alias: Record
- appDir: string,
- buildDir: string,
- vite: boolean,
- buildModules: NuxtModule[]
- createRequire?: (module: NodeJS.Module) => NodeJS.Require
- debug?: boolean
- dev: boolean
- dir: { [key in 'app' | 'assets' | 'layouts' | 'middleware' | 'pages' | 'static' | 'store']: string }
- editor: undefined
- env: NodeJS.ProcessEnv
- extensions: string[]
- globalName?: string,
- globals: {
- id: (globalName: string) => string
- nuxt: (globalName: string) => string
- context: (globalName: string) => string
- pluginPrefix: (globalName: string) => string
- readyCallback: (globalName: string) => string
- loadedCallback: (globalName: string) => string
- }
- hooks: null | ((hook: Hookable['hook']) => void) | NuxtHooks
- ignoreOptions?: IgnoreOptions
- ignorePrefix: string
- ignore: Array
- // TODO: remove in Nuxt 3
- mode: Mode
- modern?: boolean | 'client' | 'server'
- modules: NuxtModule[]
- privateRuntimeConfig: Record | ((env: NodeJS.ProcessEnv) => Record)
- publicRuntimeConfig: Record | ((env: NodeJS.ProcessEnv) => Record)
- serverMiddleware: Array | Record
- ssr: boolean
- target: Target
- test: boolean
- srcDir?: string
- modulesDir: string[]
- styleExtensions: string[]
- watch: string[]
- watchers: {
- webpack: WebpackConfiguration['watchOptions']
- chokidar: ChokidarWatchOptions
- }
-}
-
-export default (): CommonConfiguration => ({
- _majorVersion: undefined,
- // Env
- dev: Boolean(env.dev),
- test: Boolean(env.test),
- debug: undefined, // = dev
- env: {},
-
- createRequire: undefined,
-
- // Target
- target: TARGETS.server,
-
- // Rendering
- ssr: true,
-
- // TODO: remove in Nuxt 3
- // Mode
- mode: MODES.universal,
- modern: undefined,
-
- // Modules
- modules: [],
- buildModules: [],
- _modules: [],
-
- globalName: undefined,
- globals: {
- id: globalName => `__${globalName}`,
- nuxt: globalName => `$${globalName}`,
- context: globalName => `__${globalName.toUpperCase()}__`,
- pluginPrefix: globalName => globalName,
- readyCallback: globalName => `on${capitalize(globalName)}Ready`,
- loadedCallback: globalName => `_on${capitalize(globalName)}Loaded`
- },
-
- // Server
- serverMiddleware: [],
-
- // Dirs and extensions
- _nuxtConfigFile: undefined,
- srcDir: undefined,
- buildDir: '.nuxt',
- vite: false,
- modulesDir: [
- 'node_modules'
- ],
- appDir: APP_DIR,
- dir: {
- assets: 'assets',
- app: 'app',
- layouts: 'layouts',
- middleware: 'middleware',
- pages: 'pages',
- static: 'static',
- store: 'store'
- },
- extensions: [],
- styleExtensions: ['css', 'pcss', 'postcss', 'styl', 'stylus', 'scss', 'sass', 'less'],
- alias: {},
-
- // Ignores
- ignoreOptions: undefined,
- ignorePrefix: '_',
- ignore: [
- '**/*.test.*',
- '**/*.spec.*'
- ],
-
- // Watch
- watch: [],
- watchers: {
- webpack: {
- aggregateTimeout: 1000
- },
- chokidar: {
- ignoreInitial: true
- }
- },
-
- // Editor
- editor: undefined,
-
- // Hooks
- hooks: null,
-
- // runtimeConfig
- privateRuntimeConfig: {},
- publicRuntimeConfig: {}
-})
diff --git a/packages/nuxt3/src/config/config/build.ts b/packages/nuxt3/src/config/config/build.ts
deleted file mode 100644
index 6a44cf0cbc..0000000000
--- a/packages/nuxt3/src/config/config/build.ts
+++ /dev/null
@@ -1,369 +0,0 @@
-import env from 'std-env'
-import type { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
-
-import type { TransformOptions, PluginItem } from '@babel/core'
-import type { Options as AutoprefixerOptions } from 'autoprefixer'
-import type { Options as FileLoaderOptions } from 'file-loader'
-import type { Options as HtmlMinifierOptions } from 'html-minifier'
-import type * as Less from 'less'
-import type { Options as SassOptions } from 'sass'
-import type { Plugin as PostcssPlugin } from 'postcss'
-import type { Options as PugOptions } from 'pug'
-import type { TerserPluginOptions } from 'terser-webpack-plugin'
-import type { VueLoaderOptions } from 'vue-loader'
-import type {
- Configuration as WebpackConfiguration, WebpackPluginFunction
-
-} from 'webpack'
-import type { Options as WebpackDevMiddlewareOptions } from 'webpack-dev-middleware'
-import type { MiddlewareOptions as WebpackHotMiddlewareOptions, ClientOptions as WebpackHotMiddlewareClientOptions } from 'webpack-hot-middleware'
-
-interface WebpackEnv {
- isClient: boolean
- isDev: boolean
- isLegacy: boolean
- isModern: boolean
- isServer: boolean
-}
-
-interface BabelPresetEnv {
- envName: 'client' | 'modern' | 'server'
-}
-interface Warning {
- message: string
- name: string
-}
-
-interface BabelOptions extends Pick> {
- cacheCompression?: boolean
- cacheDirectory?: boolean
- cacheIdentifier?: string
- customize?: string | null
- presets?: ((env: BabelPresetEnv & WebpackEnv, defaultPreset: [string, object]) => PluginItem[] | void) | PluginItem[] | null
- plugins?: ((env: BabelPresetEnv & WebpackEnv) => NonNullable) | TransformOptions['plugins']
-}
-
-type CssLoaderUrlFunction = (url: string, resourcePath: string) => boolean
-type CssLoaderImportFunction = (parsedImport: string, resourcePath: string) => boolean
-type CssLoaderMode = 'global' | 'local'
-interface CssLoaderModulesOptions {
- context?: string
- getLocalIdent?: (context: string, localIdentName: string, localName: string, options: CssLoaderModulesOptions) => string
- hashPrefix?: string
- localIdentName?: string
- localIdentRegExp?: string | RegExp
- mode?: CssLoaderMode
-}
-interface CssLoaderOptions {
- import?: boolean | CssLoaderImportFunction
- importLoaders?: number
- localsConvention?: 'asIs' | 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'
- modules?: boolean | CssLoaderMode | CssLoaderModulesOptions
- onlyLocals?: boolean
- sourceMap?: boolean
- url?: boolean | CssLoaderUrlFunction
-}
-
-interface UrlLoaderOptions {
- esModule?: boolean
- // TODO
- fallback?: any // WebpackLoader
- limit?: boolean | number | string
- mimetype?: string
-}
-
-interface PostcssOrderPresetFunctions {
- cssnanoLast: (names: string[]) => string[]
- presetEnvAndCssnanoLast: (names: string[]) => string[]
- presetEnvLast: (names: string[]) => string[]
-}
-type PostcssOrderPreset = keyof PostcssOrderPresetFunctions
-interface PostcssVariableMap {
- customMedia: Record
- customProperties: Record
- customSelectors: Record
- environmentVariables?: Record
-}
-
-interface PostcssConfiguration {
- order?: PostcssOrderPreset | string[] | ((names: string[], presets: PostcssOrderPresetFunctions) => string[])
- plugins?: {
- [key: string]: false | { [key: string]: any }
- } | ((loader: any) => PostcssPlugin[]) | Array<[string | PostcssPlugin, any] | string | PostcssPlugin>
- preset?: {
- autoprefixer?: false | AutoprefixerOptions
- browsers?: string
- exportTo?: string | string[] | Partial | ((map: PostcssVariableMap) => Partial)
- features?: {
- [key: string]: boolean | { [key: string]: any }
- }
- importFrom?: string | string[] | Partial | (() => Partial)
- insertAfter?: { [key: string]: PostcssPlugin }
- insertBefore?: { [key: string]: PostcssPlugin }
- preserve?: boolean
- stage?: 0 | 1 | 2 | 3 | 4 | false
- }
-}
-
-interface Loaders {
- css?: CssLoaderOptions
- cssModules?: CssLoaderOptions
- file?: FileLoaderOptions
- fontUrl?: UrlLoaderOptions
- imgUrl?: UrlLoaderOptions
- less?: Less.Options
- pugPlain?: PugOptions
- sass?: SassOptions
- scss?: SassOptions
- stylus?: any // TBD
- vue?: VueLoaderOptions
- vueStyle?: {
- manualInject?: boolean
- ssrId?: boolean
- shadowMode?: boolean
- }
-}
-
-export interface Template {
- /**
- * Source file. Can be absolute or relative.
- */
- src: string,
- /**
- * Destination file within `.nuxt` filter. This filename should be relative to the project `.nuxt` dir
- */
- dst: string,
- /**
- * Options are provided to template as `options` key
- */
- options?: Record
-}
-
-export default () => ({
- /**
- * @private
- */
- _publicPath: '/_nuxt/',
-
- additionalExtensions: [] as string[],
- aggressiveCodeRemoval: false,
- /**
- * Use [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) to let you visualize your bundles and how to optimize them.
- * @default false
- */
- analyze: false as boolean | BundleAnalyzerPlugin.Options,
- babel: {
- configFile: false,
- babelrc: false,
- cacheDirectory: undefined
- } as BabelOptions,
- /**
- * Enable cache of [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin#options) and [cache-loader](https://github.com/webpack-contrib/cache-loader#cache-loader)
- *
- * ⚠️ Experimental
- * @default false
- */
- cache: false,
- corejs: undefined as undefined | 'auto' | 2 | 3,
- crossorigin: undefined as undefined | string,
- /**
- * Enables CSS Source Map support.
- * @default true for dev and `false` for production
- */
- cssSourceMap: undefined as undefined | boolean,
- devMiddleware: {} as WebpackDevMiddlewareOptions,
- devtools: undefined as undefined | boolean,
- extend: null as null | ((
- config: WebpackConfiguration,
- ctx: {
- loaders: Loaders
- } & WebpackEnv
- ) => void),
- /**
- * Enables Common CSS Extraction using Vue Server Renderer guidelines.
- *
- * Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, all your CSS will be extracted into separate files, usually one per component. This allows caching your CSS and JavaScript separately and is worth a try in case you have a lot of global or shared CSS.
- *
- * @default false
- */
- extractCSS: false as boolean | Record,
- /**
- * Customize bundle filenames.
- */
- filenames: {
- app: ({ isDev, isModern }: WebpackEnv) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
- chunk: ({ isDev, isModern }: WebpackEnv) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
- css: ({ isDev }: WebpackEnv) => isDev ? '[name].css' : '[name].[contenthash:7].css',
- img: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
- font: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
- video: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
- },
- /**
- * By default, the build process does not scan files inside symlinks. This boolean includes them, thus allowing usage of symlinks inside folders such as the "pages" folder, for example.
- * @default false
- */
- followSymlinks: false,
- /**
- * Enables or disables the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin)
- * @default true
- */
- friendlyErrors: true,
- hardSource: false,
- hotMiddleware: {} as WebpackHotMiddlewareOptions & { client?: WebpackHotMiddlewareClientOptions },
- html: {
- /**
- * Configuration for the [html-minifier plugin](https://github.com/kangax/html-minifier) used to minify HTML files created during the build process (will be applied for all modes).
- */
- minify: {
- collapseBooleanAttributes: true,
- decodeEntities: true,
- minifyCSS: true,
- minifyJS: true,
- processConditionalComments: true,
- removeEmptyAttributes: true,
- removeRedundantAttributes: true,
- trimCustomFragments: true,
- useShortDoctype: true
- }
- } as { minify: HtmlMinifierOptions },
- indicator: {
- position: 'bottom-right',
- backgroundColor: '#2E495E',
- color: '#00C48D'
- } as boolean | { position: string, backgroundColor: string, color: string },
- /**
- * Customize options of Nuxt.js integrated webpack loaders.
- */
- loaders: {
- /**
- * Mor details at https://github.com/webpack-contrib/file-loader#options
- */
- file: {},
- fontUrl: { limit: 1000 },
- imgUrl: { limit: 1000 },
- pugPlain: {},
- vue: {
- transformAssetUrls: {
- video: 'src',
- source: 'src',
- object: 'src',
- embed: 'src'
- }
- },
- css: {
- esModule: false
- },
- cssModules: {
- esModule: false,
- modules: {
- localIdentName: '[local]_[hash:base64:5]'
- }
- },
- less: {},
- sass: {
- sassOptions: {
- indentedSyntax: true
- }
- },
- scss: {},
- // tODO
- stylus: {},
- vueStyle: {}
- } as Loaders,
- loadingScreen: {} as Record | false,
- optimizeCSS: undefined as Record | false | undefined,
- optimization: {
- minimize: undefined as boolean | undefined,
- minimizer: undefined,
- splitChunks: {
- chunks: 'all',
- name: undefined,
- cacheGroups: {
- default: {
- name: undefined
- }
- }
- }
- } as WebpackConfiguration['optimization'],
- /**
- * Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) in webpack building
- *
- * ⚠️ Experimental
- * @default false
- */
- parallel: false,
- plugins: [] as WebpackPluginFunction[],
- postcss: {
- preset: {
- // https://cssdb.org/#staging-process
- stage: 2
- }
- } as string[] | boolean | PostcssConfiguration | (() => PostcssConfiguration),
- /**
- * Enable the profiler in [WebpackBar](https://github.com/nuxt/webpackbar#profile)
- * @default false unless enabled by command line argument `--profile`
- */
- profile: process.argv.includes('--profile'),
- /**
- * Nuxt.js lets you upload your dist files to your CDN for maximum performances, simply set the `publicPath` to your CDN.
- * @default '/_nuxt/'
- * @example
- ```
- export default {
- build: {
- publicPath: 'https://cdn.nuxtjs.org'
- }
- }
- ```
- Then, when launching nuxt build, upload the content of .nuxt/dist/client directory to your CDN and voilà!
- */
- publicPath: '/_nuxt/',
- /**
- * Suppresses most of the build output log
- * @default true when a CI or test environment is detected by [std-env](https://github.com/nuxt-contrib/std-env)
- */
- quiet: Boolean(env.ci || env.test),
- /**
- * @default 'url'
- */
- serverURLPolyfill: 'url',
- splitChunks: {
- layouts: false,
- pages: true,
- commons: true
- },
- /**
- * Creates special webpack bundle for SSR renderer.
- * @default true for universal mode and `false` for spa mode
- */
- ssr: undefined as undefined | boolean,
- /**
- *
- */
- standalone: false,
- stats: {
- excludeAssets: [
- /.map$/,
- /index\..+\.html$/,
- /vue-ssr-(client|modern)-manifest.json/
- ]
- } as 'none' | false | { excludeAssets: RegExp[] },
- styleResources: {},
- template: undefined,
- /**
- * Nuxt.js allows you provide your own templates which will be rendered based on Nuxt configuration. This feature is specially useful for using with modules.
- */
- templates: [] as Template[],
- /**
- * Terser plugin options. Set to `false` to disable this plugin. See https://github.com/webpack-contrib/terser-webpack-plugin
- */
- terser: {} as TerserPluginOptions | boolean,
- // Name of NPM packages to be transpiled
- transpile: [] as Array string | RegExp | undefined)>,
- warningIgnoreFilters: [] as Array<(warn: Warning) => boolean>,
- /**
- * You can provide your custom files to watch and regenerate after changes. This feature is specially useful for using with modules.
- */
- watch: [] as string[]
-
-})
diff --git a/packages/nuxt3/src/config/config/cli.ts b/packages/nuxt3/src/config/config/cli.ts
deleted file mode 100644
index 48ad13cfea..0000000000
--- a/packages/nuxt3/src/config/config/cli.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Color } from 'chalk'
-
-export interface CliOptions {
- badgeMessages: string[]
- bannerColor: typeof Color
-}
-
-export default (): CliOptions => ({
- badgeMessages: [],
- bannerColor: 'green'
-})
diff --git a/packages/nuxt3/src/config/config/generate.ts b/packages/nuxt3/src/config/config/generate.ts
deleted file mode 100644
index b7e103bc44..0000000000
--- a/packages/nuxt3/src/config/config/generate.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { GlobbyOptions } from 'globby'
-
-type GenerateRoute = string | { route: string, payload: any }
-
-type GenerateRoutesFunction = () => (Promise | GenerateRoute[])
-type GenerateRoutesFunctionWithCallback = (callback: (err: Error, routes: GenerateRoute[]) => void) => void
-
-export interface GenerateOptions {
- cache?: false | {
- ignore?: string[] | Function,
- globbyOptions?: GlobbyOptions
- }
- concurrency: number
- crawler: boolean
- devtools?: boolean
- dir: string
- exclude: RegExp[]
- fallback: boolean | string
- interval: number
- routes: GenerateRoute[] | GenerateRoutesFunction | GenerateRoutesFunctionWithCallback
- staticAssets: {
- base?: string
- versionBase?: string
- dir?: string
- version?: string
- }
- subFolders: boolean
-}
-
-export default (): GenerateOptions => ({
- dir: 'dist',
- routes: [],
- exclude: [],
- concurrency: 500,
- interval: 0,
- subFolders: true,
- fallback: '200.html',
- crawler: true,
- staticAssets: {
- base: undefined, // Default: "/_nuxt/static:
- versionBase: undefined, // Default: "_nuxt/static/{version}""
- dir: 'static',
- version: undefined // Default: "{timeStampSec}"
- }
-})
diff --git a/packages/nuxt3/src/config/config/index.ts b/packages/nuxt3/src/config/config/index.ts
deleted file mode 100644
index 89987c7a6e..0000000000
--- a/packages/nuxt3/src/config/config/index.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-
-import _app from './_app'
-import _common from './_common'
-
-import build from './build'
-import messages from './messages'
-import modes from './modes'
-import render from './render'
-import router from './router'
-import server from './server'
-import cli from './cli'
-import generate, { GenerateOptions } from './generate'
-
-export const defaultNuxtConfigFile = 'nuxt.config'
-
-export const getDefaultNuxtConfig = () =>
- ({
- ..._app(),
- ..._common(),
- build: build(),
- messages: messages(),
- modes: modes(),
- render: render(),
- router: router(),
- server: server({ env: process.env }) as ReturnType | boolean,
- cli: cli(),
- generate: generate(),
- export: undefined as undefined | GenerateOptions,
- telemetry: undefined as undefined | boolean
- })
-
-export type DefaultConfiguration = ReturnType
diff --git a/packages/nuxt3/src/config/config/messages.ts b/packages/nuxt3/src/config/config/messages.ts
deleted file mode 100644
index 0c3694c2b5..0000000000
--- a/packages/nuxt3/src/config/config/messages.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export default () => ({
- loading: 'Loading...',
- error_404: 'This page could not be found',
- server_error: 'Server error',
- nuxtjs: 'Nuxt.js',
- back_to_home: 'Back to the home page',
- server_error_details:
- 'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
- client_error: 'Error',
- client_error_details:
- 'An error occurred while rendering the page. Check developer tools console for details.'
-})
diff --git a/packages/nuxt3/src/config/config/modes.ts b/packages/nuxt3/src/config/config/modes.ts
deleted file mode 100644
index 93402f21e8..0000000000
--- a/packages/nuxt3/src/config/config/modes.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { MODES } from '../../utils'
-
-export default () => ({
- [MODES.universal]: {
- build: {
- ssr: true
- },
- render: {
- ssr: true
- }
- } as const,
- [MODES.spa]: {
- build: {
- ssr: false
- },
- render: {
- ssr: false
- }
- } as const
-})
diff --git a/packages/nuxt3/src/config/config/render.ts b/packages/nuxt3/src/config/config/render.ts
deleted file mode 100644
index 85153e9e9d..0000000000
--- a/packages/nuxt3/src/config/config/render.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-// TODO: Refactor @nuxt/server related options into `server.js`
-import type { ServerResponse, IncomingMessage } from 'http'
-import type { CompressionOptions } from 'compression'
-import type { ServeStaticOptions } from 'serve-static'
-import type etag from 'etag'
-import type { ServerMiddleware } from './_common'
-
-interface PreloadFile {
- asType: 'script' | 'style' | 'font'
- extension: string
- file: string
- fileWithoutQuery: string
-}
-
-type ServePlaceholderHandler = 'default' | 'css' | 'html' | 'js' | 'json' | 'map' | 'plain' | 'image'
-interface ServePlaceholderOptions {
- handlers?: Record
- mimes?: Record
- noCache?: boolean
- placeholders?: Record
- skipUnknown?: boolean
- statusCode?: false | number
-}
-
-type CspPolicyName = 'child-src' | 'connect-src' | 'default-src' | 'font-src' | 'frame-src' | 'img-src' | 'manifest-src' | 'media-src' | 'object-src' | 'prefetch-src' | 'script-src' | 'script-src-elem' | 'script-src-attr' | 'style-src' | 'style-src-elem' | 'style-src-attr' | 'worker-src' | 'base-uri' | 'plugin-types' | 'sandbox' | 'form-action' | 'frame-ancestors' | 'navigate-to' | 'report-uri' | 'report-to' | 'block-all-mixed-content' | 'referrer' | 'require-sri-for' | 'trusted-types' | 'upgrade-insecure-requests'
-
-interface RenderOptions {
- bundleRenderer: {
- shouldPrefetch: (fileWithoutQuery: string, asType: string) => boolean
- shouldPreload: (fileWithoutQuery: string, asType: string) => boolean
- runInNewContext?: boolean
- }
- compressor: CompressionOptions | ServerMiddleware | false
- crossorigin?: 'anonymous' | 'use-credentials' | ''
- csp: boolean | {
- addMeta?: boolean
- allowedSources?: string[]
- hashAlgorithm?: string
- policies?: Record
- reportOnly?: boolean
- unsafeInlineCompatibility?: boolean
- }
- dist: ServeStaticOptions
- etag: false | etag.Options & {
- hash?: (html: string) => string
- }
- fallback?: {
- dist?: ServePlaceholderOptions
- static?: ServePlaceholderOptions
- }
- /**
- * @deprecated
- */
- gzip?: CompressionOptions | ServerMiddleware | false
- http2?: {
- push?: boolean
- shouldPush?: boolean | null
- pushAssets?: null | ((
- req: IncomingMessage,
- res: ServerResponse,
- publicPath: string,
- preloadFiles: PreloadFile[]
- ) => string[])
- }
- injectScripts?: boolean
- resourceHints: boolean
- ssr?: boolean
- ssrLog?: boolean | 'collapsed'
- static: ServeStaticOptions & { prefix?: string }
-}
-
-export default (): RenderOptions => ({
- bundleRenderer: {
- shouldPrefetch: () => false,
- shouldPreload: (_fileWithoutQuery, asType) => ['script', 'style'].includes(asType),
- runInNewContext: undefined
- },
- crossorigin: undefined,
- resourceHints: true,
- ssr: undefined,
- ssrLog: undefined,
- http2: {
- push: false,
- shouldPush: null,
- pushAssets: null
- },
- static: {},
- compressor: {
- threshold: 0
- },
- etag: {
- weak: false
- },
- csp: false,
- dist: {
- // Don't serve index.html template
- index: false,
- // 1 year in production
- maxAge: '1y'
- },
- // https://github.com/nuxt/serve-placeholder
- fallback: {
- dist: {},
- static: {
- skipUnknown: true,
- handlers: {
- '.htm': false,
- '.html': false
- }
- }
- }
-})
diff --git a/packages/nuxt3/src/config/config/router.ts b/packages/nuxt3/src/config/config/router.ts
deleted file mode 100644
index f7228ae837..0000000000
--- a/packages/nuxt3/src/config/config/router.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { RouteRecordRaw, RouterScrollBehavior } from 'vue-router'
-
-type UnionToIntersection = (T extends any ? (k: T) => void : never) extends ((k: infer U) => void) ? U : never
-type RouteConfig = UnionToIntersection
-
-export interface Route extends Pick> {
- children?: Route[]
- chunkName?: string
- chunkNames?: Record
- component?: RouteConfig['component'] | string
-}
-interface Middleware { }
-
-export interface RouterConfigurationNormalized {
- base: string
- extendRoutes?(routes: Route[], resolve: (...pathSegments: string[]) => string): void
- fallback: boolean
- linkActiveClass: string | false
- linkExactActiveClass: string | false
- linkPrefetchedClass: string | false
- middleware: Middleware[]
- mode: 'history' | 'hash'
- parseQuery: boolean
- prefetchLinks: boolean
- prefetchPayloads: boolean
- routes: Route[]
- routeNameSplitter: string
- scrollBehavior: null | RouterScrollBehavior
- stringifyQuery: boolean
- trailingSlash?: boolean
-}
-
-export default (): RouterConfigurationNormalized => ({
- mode: 'history',
- base: '/',
- routes: [],
- routeNameSplitter: '-',
- middleware: [],
- linkActiveClass: 'nuxt-link-active',
- linkExactActiveClass: 'nuxt-link-exact-active',
- linkPrefetchedClass: false,
- extendRoutes: null,
- scrollBehavior: null,
- parseQuery: false,
- stringifyQuery: false,
- fallback: false,
- prefetchLinks: true,
- prefetchPayloads: true,
- trailingSlash: undefined
-})
diff --git a/packages/nuxt3/src/config/config/server.ts b/packages/nuxt3/src/config/config/server.ts
deleted file mode 100644
index 5c8e7a77a3..0000000000
--- a/packages/nuxt3/src/config/config/server.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-export interface ServerProcessEnv extends NodeJS.ProcessEnv {
- NUXT_HOST?: string
- NUXT_PORT?: string
- HOST?: string
- PORT?: string
- UNIX_SOCKET?: string
- // eslint-disable-next-line camelcase
- npm_package_config_nuxt_port?: string
- // eslint-disable-next-line camelcase
- npm_package_config_nuxt_host?: string
- // eslint-disable-next-line camelcase
- npm_package_config_unix_socket?: string
-}
-
-export default ({ env = {} }: { env?: ServerProcessEnv } = {}) => ({
- https: false as false | {
- cert?: string | Buffer
- key?: string | Buffer
- },
- port: env.NUXT_PORT ||
- env.PORT ||
- env.npm_package_config_nuxt_port ||
- 3000,
- host: env.NUXT_HOST ||
- env.HOST ||
- env.npm_package_config_nuxt_host ||
- 'localhost',
- socket: env.UNIX_SOCKET ||
- env.npm_package_config_unix_socket,
- timing: false as false | { total: boolean }
-})
diff --git a/packages/nuxt3/src/config/index.ts b/packages/nuxt3/src/config/index.ts
deleted file mode 100644
index 8acbffd7b3..0000000000
--- a/packages/nuxt3/src/config/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export { defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
-export { getNuxtConfig, Configuration, NormalizedConfiguration } from './options'
-export { loadNuxtConfig } from './load'
diff --git a/packages/nuxt3/src/config/load.ts b/packages/nuxt3/src/config/load.ts
deleted file mode 100644
index 61b24fc440..0000000000
--- a/packages/nuxt3/src/config/load.ts
+++ /dev/null
@@ -1,196 +0,0 @@
-import path from 'path'
-import fs from 'fs'
-import defu from 'defu'
-import consola from 'consola'
-import dotenv from 'dotenv'
-import jiti from 'jiti'
-import _createRequire from 'create-require'
-import destr from 'destr'
-import * as rc from 'rc9'
-import { clearRequireCache, scanRequireTree } from '../utils'
-
-import { LoadOptions } from '../core/load'
-import { CliConfiguration, Configuration } from '../config/options'
-import { defaultNuxtConfigFile } from './config'
-
-// @ts-ignore
-const isJest = typeof jest !== 'undefined'
-
-const interopDefault = (obj: any) => {
- return 'default' in obj ? obj.default : obj
-}
-
-export interface EnvConfig {
- dotenv?: string
- env?: NodeJS.ProcessEnv & { _applied?: boolean }
- expand?: boolean
-}
-
-export async function loadNuxtConfig ({
- rootDir = '.',
- envConfig = {},
- configFile = defaultNuxtConfigFile,
- configContext = {},
- configOverrides = {},
- createRequire = (module: NodeJS.Module) => isJest ? _createRequire(module.filename) : jiti(module.filename)
-}: LoadOptions = {}) {
- rootDir = path.resolve(rootDir)
-
- let options: CliConfiguration = {}
-
- try {
- configFile = require.resolve(path.resolve(rootDir, configFile))
- } catch (e) {
- if (e.code !== 'MODULE_NOT_FOUND') {
- throw (e)
- } else if (configFile !== defaultNuxtConfigFile) {
- consola.fatal('Config file not found: ' + configFile)
- }
- // Skip configFile if cannot resolve
- configFile = undefined
- }
-
- // Load env
- envConfig = {
- dotenv: '.env',
- env: process.env,
- expand: true,
- ...envConfig
- }
-
- const env = loadEnv(envConfig, rootDir)
-
- // Fill process.env so it is accessible in nuxt.config
- for (const key in env) {
- if (!key.startsWith('_') && envConfig.env[key] === undefined) {
- envConfig.env[key] = env[key]
- }
- }
-
- if (configFile) {
- // Clear cache
- clearRequireCache(configFile)
- const _require = createRequire(module)
- let _config: Configuration | ((ctx: Record) => Promise) = interopDefault(_require(configFile) || {})
-
- if (typeof _config === 'function') {
- try {
- _config = interopDefault(await _config(configContext))
- } catch (error) {
- consola.error(error)
- consola.fatal('Error while fetching async configuration')
- }
- }
-
- // Don't mutate options export
- options = { ..._config }
-
- // Keep _nuxtConfigFile for watching
- options._nuxtConfigFile = configFile
-
- // Keep all related files for watching
- options._nuxtConfigFiles = Array.from(scanRequireTree(configFile))
- if (!options._nuxtConfigFiles.includes(configFile)) {
- options._nuxtConfigFiles.unshift(configFile)
- }
- }
-
- if (typeof options.rootDir !== 'string') {
- options.rootDir = rootDir
- }
-
- // Load Combine configs
- // Priority: configOverrides > nuxtConfig > .nuxtrc > .nuxtrc (global)
- options = defu(
- configOverrides,
- options,
- rc.read({ name: '.nuxtrc', dir: options.rootDir }),
- rc.readUser('.nuxtrc')
- )
-
- // Load env to options._env
- options._env = env
- options._envConfig = envConfig
- if (configContext) { configContext.env = env }
-
- // Expand and interpolate runtimeConfig from _env
- if (envConfig.expand) {
- for (const c of ['publicRuntimeConfig', 'privateRuntimeConfig']) {
- if (options[c]) {
- if (typeof options[c] === 'function') {
- options[c] = options[c](env)
- }
- expand(options[c], env, destr)
- }
- }
- }
-
- return options
-}
-
-function loadEnv (envConfig: EnvConfig, rootDir = process.cwd()) {
- const env = Object.create(null)
-
- // Read dotenv
- if (envConfig.dotenv) {
- envConfig.dotenv = path.resolve(rootDir, envConfig.dotenv)
- if (fs.existsSync(envConfig.dotenv)) {
- const parsed = dotenv.parse(fs.readFileSync(envConfig.dotenv, 'utf-8'))
- Object.assign(env, parsed)
- }
- }
-
- // Apply process.env
- if (!envConfig.env._applied) {
- Object.assign(env, envConfig.env)
- envConfig.env._applied = true
- }
-
- // Interpolate env
- if (envConfig.expand) {
- expand(env)
- }
-
- return env
-}
-
-// Based on https://github.com/motdotla/dotenv-expand
-function expand (target: Record, source: Record = {}, parse = (v: string) => v) {
- function getValue (key: string) {
- // Source value 'wins' over target value
- return source[key] !== undefined ? source[key] : target[key]
- }
-
- function interpolate (value: string): string {
- if (typeof value !== 'string') {
- return value
- }
- const matches = value.match(/(.?\${?(?:[a-zA-Z0-9_:]+)?}?)/g) || []
- return parse(matches.reduce((newValue, match) => {
- const parts = /(.?)\${?([a-zA-Z0-9_:]+)?}?/g.exec(match)
- const prefix = parts[1]
-
- let value: string
- let replacePart: string
-
- if (prefix === '\\') {
- replacePart = parts[0]
- value = replacePart.replace('\\$', '$')
- } else {
- const key = parts[2]
- replacePart = parts[0].substring(prefix.length)
-
- value = getValue(key)
-
- // Resolve recursive interpolations
- value = interpolate(value)
- }
-
- return newValue.replace(replacePart, value)
- }, value))
- }
-
- for (const key in target) {
- target[key] = interpolate(getValue(key))
- }
-}
diff --git a/packages/nuxt3/src/config/options.ts b/packages/nuxt3/src/config/options.ts
deleted file mode 100644
index 1c2f9d17d4..0000000000
--- a/packages/nuxt3/src/config/options.ts
+++ /dev/null
@@ -1,453 +0,0 @@
-import path from 'path'
-import fs from 'fs'
-import consola from 'consola'
-import defu from 'defu'
-import defaultsDeep from 'lodash/defaultsDeep'
-import pick from 'lodash/pick'
-import uniq from 'lodash/uniq'
-import destr from 'destr'
-import { TARGETS, MODES, guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule, urlJoin, getPKG } from '../utils'
-import type { EnvConfig } from '../config/load'
-import { DefaultConfiguration, defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
-import { deleteProp, mergeConfigs, setProp, overrideProp, Optional } from './transformers'
-
-interface InputConfiguration {
- documentPath?: string
- layoutTransition?: string | DefaultConfiguration['layoutTransition']
- loading?: true | false | DefaultConfiguration['loading']
- manifest?: {
- // eslint-disable-next-line camelcase
- theme_color?: string
- }
- pageTransition?: string | DefaultConfiguration['pageTransition']
- rootDir?: string
- store?: boolean
-}
-
-export interface Configuration extends InputConfiguration, Optional> { }
-
-export interface CliConfiguration extends Configuration {
- // cli
- _build?: boolean
- _cli?: boolean
- _export?: boolean
- _generate?: boolean
- _start?: boolean
- _ready?: boolean
- _legacyGenerate?: boolean
- _env?: NodeJS.ProcessEnv
- _envConfig?: EnvConfig
- _nuxtConfigFiles?: string[]
-}
-
-export function getNuxtConfig (_options: Configuration) {
- // Prevent duplicate calls
- if ('__normalized__' in _options) {
- return _options
- }
-
- return normalizeConfig(_options as CliConfiguration)
-}
-
-function normalizeConfig (_options: CliConfiguration) {
- // Clone options to prevent unwanted side-effects
- const _config: CliConfiguration = Object.assign({}, _options)
-
- setProp(_config, '__normalized__', true as const)
-
- // Normalize options
- if (_config.loading === true) {
- deleteProp(_config, 'loading')
- }
-
- setProp(_config, '_routerBaseSpecified', _config.router && typeof _config.router.base === 'string')
-
- overrideProp(_config, 'pageTransition', typeof _config.pageTransition === 'string' ? { name: _config.pageTransition } : _config.pageTransition)
- overrideProp(_config, 'layoutTransition', typeof _config.layoutTransition === 'string' ? { name: _config.layoutTransition } : _config.layoutTransition)
-
- if (typeof _config.extensions === 'string') {
- _config.extensions = [_config.extensions]
- }
-
- overrideProp(_config, 'globalName',
- (isNonEmptyString(_config.globalName) && /^[a-zA-Z]+$/.test(_config.globalName))
- ? _config.globalName.toLowerCase()
- // use `` for preventing replacing to nuxt-edge
- : 'nuxt'
- )
-
- // Resolve rootDir
- overrideProp(_config, 'rootDir',
- isNonEmptyString(_config.rootDir) ? path.resolve(_config.rootDir) : process.cwd()
- )
-
- // Apply defaults by ${buildDir}/dist/build.config.js
- // TODO: Unsafe operation.
- // const buildDir = _config.buildDir || defaults.buildDir
- // const buildConfig = resolve(_config.rootDir, buildDir, 'build.config.js')
- // if (existsSync(buildConfig)) {
- // defaultsDeep(_config, require(buildConfig))
- // }
-
- // Fall back to default if publicPath is falsy
- if (_config.build && !_config.build.publicPath) {
- _config.build.publicPath = undefined
- }
-
- // Apply defaults
- const options = mergeConfigs(_config, getDefaultNuxtConfig())
-
- // Target
- if (!Object.values(TARGETS).includes(options.target)) {
- consola.warn(`Unknown target: ${options.target}. Falling back to server`)
- options.target = 'server'
- }
-
- // SSR root option
- if (options.ssr === false) {
- options.mode = MODES.spa
- }
-
- // Apply mode preset
- const modePreset = options.modes[options.mode || MODES.universal]
-
- if (!modePreset) {
- consola.warn(`Unknown mode: ${options.mode}. Falling back to ${MODES.universal}`)
- }
- defaultsDeep(options, modePreset || options.modes[MODES.universal])
-
- // Sanitize router.base
- if (!/\/$/.test(options.router.base)) {
- options.router.base += '/'
- }
-
- // Alias export to generate
- // TODO: switch to export by default for nuxt3
- if (options.export) {
- options.generate = defu(options.export, options.generate)
- }
- exports.export = options.generate
-
- // Check srcDir and generate.dir existence
- const hasSrcDir = isNonEmptyString(options.srcDir)
- const hasGenerateDir = isNonEmptyString(options.generate.dir)
-
- // Resolve srcDir
- overrideProp(options, 'srcDir', hasSrcDir
- ? path.resolve(options.rootDir, options.srcDir)
- : options.rootDir)
-
- // Resolve buildDir
- overrideProp(options, 'buildDir', path.resolve(options.rootDir, options.buildDir))
-
- // Aliases
- const { rootDir, srcDir, dir: { assets: assetsDir, static: staticDir } } = options
- overrideProp(options, 'alias', {
- '~~': rootDir,
- '@@': rootDir,
- '~': srcDir,
- '@': srcDir,
- [assetsDir]: path.join(srcDir, assetsDir),
- [staticDir]: path.join(srcDir, staticDir),
- ...options.alias
- })
-
- // Default value for _nuxtConfigFile
- overrideProp(options, '_nuxtConfigFile', options._nuxtConfigFile || path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`))
-
- setProp(options, '_nuxtConfigFiles', (options as any)._nuxtConfigFiles || [
- options._nuxtConfigFile
- ])
-
- // Watch for config file changes
- options.watch.push(...options._nuxtConfigFiles)
-
- // Protect rootDir against buildDir
- guardDir(options, 'rootDir', 'buildDir')
-
- if (hasGenerateDir) {
- // Resolve generate.dir
- options.generate.dir = path.resolve(options.rootDir, options.generate.dir)
-
- // Protect rootDir against buildDir
- guardDir(options, 'rootDir', 'generate.dir')
- }
-
- if (hasSrcDir) {
- // Protect srcDir against buildDir
- guardDir(options, 'srcDir', 'buildDir')
-
- if (hasGenerateDir) {
- // Protect srcDir against generate.dir
- guardDir(options, 'srcDir', 'generate.dir')
- }
- }
-
- // Populate modulesDir
- options.modulesDir = uniq(
- getMainModule().paths.concat(
- [].concat(options.modulesDir).map(dir => path.resolve(options.rootDir, dir))
- )
- )
-
- const mandatoryExtensions = ['js', 'mjs', 'ts', 'tsx', 'vue', 'jsx']
-
- overrideProp(options, 'extensions', mandatoryExtensions
- .filter(ext => !options.extensions.includes(ext))
- .concat(options.extensions))
-
- // If app.html is defined, set the template path to the user template
- if (options.documentPath === undefined) {
- options.documentPath = path.resolve(options.buildDir, 'views/app.template.html') // NITRO/Nuxt2 compat
- const userDocumentPath = path.join(options.srcDir, 'document.html')
- if (fs.existsSync(userDocumentPath)) {
- options.documentPath = userDocumentPath
- } else {
- options.watch.push(userDocumentPath)
- }
- } else {
- options.documentPath = path.resolve(options.srcDir, options.documentPath)
- }
-
- overrideProp(options.build, 'publicPath', options.build.publicPath.replace(/([^/])$/, '$1/'))
- overrideProp(options.build, '_publicPath', options.build._publicPath.replace(/([^/])$/, '$1/'))
-
- // Ignore publicPath on dev
- if (options.dev && isUrl(options.build.publicPath)) {
- options.build.publicPath = options.build._publicPath
- }
-
- // If store defined, update store options to true unless explicitly disabled
- if (
- options.store !== false &&
- fs.existsSync(path.join(options.srcDir, options.dir.store)) &&
- fs.readdirSync(path.join(options.srcDir, options.dir.store))
- .find(filename => filename !== 'README.md' && filename[0] !== '.')
- ) {
- options.store = true
- }
-
- // SPA loadingIndicator
- if (options.loadingIndicator) {
- // Normalize loadingIndicator
- if (!isPureObject(options.loadingIndicator)) {
- options.loadingIndicator = { name: options.loadingIndicator }
- }
-
- // Apply defaults
- options.loadingIndicator = Object.assign(
- {
- name: 'default',
- color: (options.loading && typeof options.loading !== 'string' && typeof options.loading !== 'boolean' && options.loading.color) || '#D3D3D3',
- color2: '#F5F5F5',
- background: (options.manifest && options.manifest.theme_color) || 'white',
- dev: options.dev,
- loading: options.messages.loading
- },
- options.loadingIndicator
- )
- }
-
- // Debug errors
- overrideProp(options, 'debug', options.debug ?? options.dev)
-
- // Validate that etag.hash is a function, if not unset it
- if (options.render.etag) {
- const { hash } = options.render.etag
- if (hash) {
- const isFn = hash instanceof Function
- if (!isFn) {
- options.render.etag.hash = undefined
-
- if (options.dev) {
- consola.warn(`render.etag.hash should be a function, received ${typeof hash} instead`)
- }
- }
- }
- }
-
- // Apply default hash to CSP option
- if (options.render.csp) {
- options.render.csp = defu(options.render.csp, {
- hashAlgorithm: 'sha256',
- allowedSources: undefined,
- policies: undefined,
- addMeta: Boolean(options.target === TARGETS.static),
- unsafeInlineCompatibility: false,
- reportOnly: options.debug
- })
- }
-
- // cssSourceMap
- overrideProp(options.build, 'cssSourceMap', options.build.cssSourceMap ?? options.dev)
-
- // babel cacheDirectory
- const babelConfig = options.build.babel
- overrideProp(options.build.babel, 'cacheDirectory', babelConfig.cacheDirectory ?? options.dev)
-
- // Vue config
- const vueConfig = options.vue.config
-
- overrideProp(options.vue.config, 'performance', vueConfig.performance !== undefined ? vueConfig.performance : options.dev)
-
- // merge custom env with variables
- const eligibleEnvVariables = pick(process.env, Object.keys(process.env).filter(k => k.startsWith('NUXT_ENV_')))
- overrideProp(options, 'env', Object.assign(options.env, eligibleEnvVariables))
-
- // Normalize ignore
- overrideProp(options, 'ignore', options.ignore ? Array.from(options.ignore) : [])
-
- // Append ignorePrefix glob to ignore
- if (typeof options.ignorePrefix === 'string') {
- options.ignore.push(`${options.ignorePrefix}*`)
- }
-
- // Compression middleware legacy
- if (options.render.gzip) {
- consola.warn('render.gzip is deprecated and will be removed in a future version! Please switch to render.compressor')
- options.render.compressor = options.render.gzip
- delete options.render.gzip
- }
-
- // If no server-side rendering, add appear true transition
- if (options.render.ssr === false && options.pageTransition) {
- options.pageTransition.appear = true
- }
-
- overrideProp(options.render, 'ssrLog', options.dev
- ? options.render.ssrLog === undefined || options.render.ssrLog
- : false)
-
- // We assume the SPA fallback path is 404.html (for GitHub Pages, Surge, etc.)
- overrideProp(options.generate, 'fallback', options.generate.fallback === true ? '404.html' : options.generate.fallback)
-
- if (options.build.stats === 'none' || options.build.quiet === true) {
- options.build.stats = false
- }
-
- // @pi0 - surely this can go
- // // Vendor backward compatibility with nuxt 1.x
- // if (typeof options.build.vendor !== 'undefined') {
- // delete options.build.vendor
- // consola.warn('vendor has been deprecated due to webpack4 optimization')
- // }
-
- // Disable CSS extraction due to incompatibility with thread-loader
- if (options.build.extractCSS && options.build.parallel) {
- options.build.parallel = false
- consola.warn('extractCSS cannot work with parallel build due to limited work pool in thread-loader')
- }
-
- // build.extractCSS.allChunks has no effect
- if (typeof options.build.extractCSS !== 'boolean' && typeof options.build.extractCSS.allChunks !== 'undefined') {
- consola.warn('build.extractCSS.allChunks has no effect from v2.0.0. Please use build.optimization.splitChunks settings instead.')
- }
-
- // Enable minimize for production builds
- if (options.build.optimization.minimize === undefined) {
- options.build.optimization.minimize = !options.dev
- }
-
- if (options.build.optimizeCSS === undefined) {
- options.build.optimizeCSS = options.build.extractCSS ? {} : false
- }
-
- const { loaders } = options.build
- // const vueLoader = loaders.vue
- // if (vueLoader.productionMode === undefined) {
- // vueLoader.productionMode = !options.dev
- // }
- const styleLoaders: Array = [
- 'css', 'cssModules', 'less',
- 'sass', 'scss', 'stylus', 'vueStyle'
- ]
- for (const name of styleLoaders) {
- const loader = loaders[name]
- if (loader && loader.sourceMap === undefined) {
- loader.sourceMap = Boolean(options.build.cssSourceMap)
- }
- }
-
- overrideProp(options.build, 'transpile', Array.from(options.build.transpile || []))
- options.build.transpile = [].concat(options.build.transpile || [])
- options.build.transpile.push('app')
-
- if (options.build.quiet === true) {
- consola.level = 0
- }
-
- // Use runInNewContext for dev mode by default
- const { bundleRenderer } = options.render
- overrideProp(options.render.bundleRenderer, 'runInNewContext', bundleRenderer.runInNewContext ?? options.dev)
-
- // const { timing } = options.server
- if (options.server && typeof options.server !== 'boolean' && options.server.timing) {
- overrideProp(options.server, 'timing', { total: true, ...options.server.timing })
- }
-
- overrideProp(options, 'serverMiddleware',
- Array.isArray(options.serverMiddleware)
- ? options.serverMiddleware
- : Object.entries(options.serverMiddleware)
- .map(([path, handler]) => ({ path, handler }))
- )
-
- // Generate staticAssets
- const { staticAssets } = options.generate
- overrideProp(options.generate.staticAssets, 'version', options.generate.staticAssets.version || String(Math.round(Date.now() / 1000)))
-
- if (!staticAssets.base) {
- const publicPath = isUrl(options.build.publicPath) ? '' : options.build.publicPath // "/_nuxt" or custom CDN URL
- staticAssets.base = urlJoin(publicPath, staticAssets.dir)
- }
- if (!staticAssets.versionBase) {
- staticAssets.versionBase = urlJoin(staticAssets.base, staticAssets.version)
- }
-
- // createRequire factory
- if (options.createRequire === undefined) {
- const createRequire = require('create-require')
- options.createRequire = module => createRequire(module.filename)
- }
-
- // ----- Builtin modules -----
-
- // Loading screen
- // Force disable for production and programmatic users
- if (!options.dev || !options._cli || !getPKG('@nuxt/loading-screen')) {
- options.build.loadingScreen = false
- }
- if (options.build.loadingScreen) {
- options._modules.push(['@nuxt/loading-screen', options.build.loadingScreen])
- } else {
- // When loadingScreen is disabled we should also disable build indicator
- options.build.indicator = false
- }
-
- // Components Module
- // TODO: Webpack5 support
- // if (!options._start && getPKG('@nuxt/components')) {
- // options._modules.push('@nuxt/components')
- // }
-
- // Nuxt Telemetry
- if (
- options.telemetry !== false &&
- !options.test &&
- !destr(process.env.NUXT_TELEMETRY_DISABLED) &&
- getPKG('@nuxt/telemetry')
- ) {
- options._modules.push('@nuxt/telemetry')
- }
-
- options._majorVersion = 3
-
- if (options.vite && !options.dev) {
- options.vite = false
- consola.warn('Vite does not support production builds yet! Using webpack...')
- }
-
- return options
-}
-
-export type NormalizedConfiguration = ReturnType
diff --git a/packages/nuxt3/src/config/transformers.ts b/packages/nuxt3/src/config/transformers.ts
deleted file mode 100644
index 00daa9cdbc..0000000000
--- a/packages/nuxt3/src/config/transformers.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { defaultsDeep } from 'lodash'
-
-export type Optional = {
- -readonly [K in keyof T]?: T[K] extends Function ? T[K] : T[K] extends RegExp ? T[K] : T[K] extends Promise ? T[K] : T[K] extends Array ? Array : Optional
-}
-
-export function setProp, K extends string, V> (obj: O, key: K, value: V): asserts obj is O & { [key in K]: V } {
- (obj as { [key in K]: V })[key] = value
-}
-
-type Override, K extends keyof O, V> = K extends Array ? {
- [P in keyof O]: K extends P ? O[P] extends Array ? Array : K | O[P] : O[P]
-} : O & { [key in K]: V }
-
-export function overrideProp, K extends keyof O, V> (obj: O, key: K, value: V): asserts obj is Override {
- (obj as { [key in K]: V })[key] = value
-}
-
-export function deleteProp, K extends string> (obj: O, key: K): asserts obj is Exclude {
- delete obj[key]
-}
-
-type MergeArrays = S extends Array ? T extends Array ? Array : T | Array : T | S
-type MergeObjects, T extends Record> = Omit & {
- // eslint-disable-next-line no-use-before-define
- -readonly [K in keyof S & keyof T]: Merge
-}
-type Merge = S extends Array ? MergeArrays : S extends Function ? S | T : S extends RegExp ? S | T : S extends Promise ? S | T : T extends Function ? S | T : S extends Record ? T extends Record ? MergeObjects : S | T : MergeArrays
-
-// let b: Merged<{ test: string, another: number[] }, { third: () => void, another: string[] }> = {} as any
-// b.another
-// let c = b
-// c.
-
-// T extends Array ? Array> : T
-
-export function mergeConfigs, Source extends Record> (dest: Dest, source: Source): Merge {
- return defaultsDeep(dest, source)
-}
diff --git a/packages/nuxt3/src/core/index.ts b/packages/nuxt3/src/core/index.ts
index 707114361d..acdb747ab0 100644
--- a/packages/nuxt3/src/core/index.ts
+++ b/packages/nuxt3/src/core/index.ts
@@ -1,5 +1,4 @@
export { default as Module } from './module'
export { default as Nuxt } from './nuxt'
export { default as Resolver } from './resolver'
-export { loadNuxtConfig } from '../config'
export { loadNuxt } from './load'
diff --git a/packages/nuxt3/src/core/load.ts b/packages/nuxt3/src/core/load.ts
index 8d99c62d00..492dfed93b 100644
--- a/packages/nuxt3/src/core/load.ts
+++ b/packages/nuxt3/src/core/load.ts
@@ -1,53 +1,17 @@
-import { EnvConfig } from '../config/load'
-import { loadNuxtConfig } from '../config'
+import { resolve } from 'path'
+import { loadNuxtConfig } from '@nuxt/kit'
import Nuxt from './nuxt'
-
-const OVERRIDES = {
- dry: { dev: false, server: false },
- dev: { dev: true, _build: true },
- build: { dev: false, server: false, _build: true },
- start: { dev: false, _start: true }
+export interface LoadNuxtOptions {
}
-export interface LoadOptions {
- for?: keyof typeof OVERRIDES
- ready?: boolean
+export async function loadNuxt (opts: LoadNuxtOptions) {
+ const options = await loadNuxtConfig(opts)
- rootDir?: string
- envConfig?: EnvConfig
- configFile?: string
- configContext?: Record,
- configOverrides?: Record,
- createRequire?: (module: NodeJS.Module) => NodeJS.Require
-}
-
-export async function loadNuxt (loadOptions: LoadOptions | LoadOptions['for']) {
- // Normalize loadOptions
- if (typeof loadOptions === 'string') {
- loadOptions = { for: loadOptions }
- }
- const { ready = true } = loadOptions
- const _for = loadOptions.for || 'dry'
-
- // Get overrides
- const override = OVERRIDES[_for]
-
- // Unsupported purpose
- if (!override) {
- throw new Error('Unsupported for: ' + _for)
- }
-
- // Load Config
- const config = await loadNuxtConfig(loadOptions)
-
- // Apply config overrides
- Object.assign(config, override)
-
- // Initiate Nuxt
- const nuxt = new Nuxt(config)
- if (ready) {
- await nuxt.ready()
- }
+ // Temp
+ options.appDir = resolve(__dirname, '../app')
+ options._majorVersion = 3
+ const nuxt = new Nuxt(options)
+ await nuxt.ready()
return nuxt
}
diff --git a/packages/nuxt3/src/core/module.ts b/packages/nuxt3/src/core/module.ts
index 4a30dc277a..09a2e6c85f 100644
--- a/packages/nuxt3/src/core/module.ts
+++ b/packages/nuxt3/src/core/module.ts
@@ -3,10 +3,8 @@ import fs from 'fs'
import hash from 'hash-sum'
import consola from 'consola'
-import type { NormalizedConfiguration } from '../config'
import { chainFn, sequence } from '../utils'
-import type { NuxtModule, ModuleHandler } from '../config/config/_common'
import Nuxt from './nuxt'
interface TemplateInput {
@@ -24,7 +22,7 @@ export default class ModuleContainer {
requiredModules: Record
- handler: ModuleHandler
+ handler
}>
constructor (nuxt: Nuxt) {
@@ -127,29 +125,29 @@ export default class ModuleContainer {
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
}
- addServerMiddleware (middleware: NormalizedConfiguration['serverMiddleware'][number]) {
+ addServerMiddleware (middleware) {
this.options.serverMiddleware.push(middleware)
}
- extendBuild (fn: NormalizedConfiguration['build']['extend']) {
+ extendBuild (fn) {
this.options.build.extend = chainFn(this.options.build.extend, fn)
}
- extendRoutes (fn: NormalizedConfiguration['router']['extendRoutes']) {
+ extendRoutes (fn) {
this.options.router.extendRoutes = chainFn(
this.options.router.extendRoutes,
fn
)
}
- requireModule (moduleOpts: NuxtModule) {
+ requireModule (moduleOpts) {
return this.addModule(moduleOpts)
}
- async addModule (moduleOpts: NuxtModule) {
- let src: string | ModuleHandler
+ async addModule (moduleOpts) {
+ let src
let options: Record
- let handler: ModuleHandler | ModuleHandler & { meta: { name: string } }
+ let handler
// Type 1: String or Function
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
@@ -224,7 +222,7 @@ export default class ModuleContainer {
return
}
}
- this.requiredModules[key] = { src, options, handler: handler as ModuleHandler }
+ this.requiredModules[key] = { src, options, handler }
}
}
diff --git a/packages/nuxt3/src/core/nuxt.ts b/packages/nuxt3/src/core/nuxt.ts
index 7a6575e332..205c7b243f 100644
--- a/packages/nuxt3/src/core/nuxt.ts
+++ b/packages/nuxt3/src/core/nuxt.ts
@@ -4,8 +4,6 @@ import isPlainObject from 'lodash/isPlainObject'
import consola from 'consola'
import Hookable from 'hookable'
-import { getNuxtConfig, Configuration, NormalizedConfiguration } from '../config'
-
import { version } from '../../package.json'
import ModuleContainer from './module'
@@ -25,7 +23,7 @@ export default class Nuxt extends Hookable {
_initCalled?: boolean
error?: Error & { statusCode?: number, headers?: IncomingHttpHeaders }
- options: NormalizedConfiguration
+ options: any
resolver: Resolver
moduleContainer: ModuleContainer
server?: any
@@ -33,11 +31,10 @@ export default class Nuxt extends Hookable {
render?: any['app']
showReady?: () => void
- constructor (options: Configuration = {}) {
+ constructor (options) {
super(consola)
- // Assign options and apply defaults
- this.options = getNuxtConfig(options)
+ this.options = options
// Create instance of core components
this.resolver = new Resolver(this)
diff --git a/scripts/build.ts b/scripts/build.ts
index c9a1f02dea..a2d6bf414e 100644
--- a/scripts/build.ts
+++ b/scripts/build.ts
@@ -56,7 +56,7 @@ async function main () {
if (entry.bundle) {
const input = resolve(ctx.rootDir, entry.input)
stubbed.push(entry.output)
- const output = resolve(ctx.rootDir, entry.output) + '.js'
+ const output = resolve(ctx.rootDir, entry.output) + '.ts'
await mkdir(dirname(output)).catch(() => { })
await writeFile(output, entry.format === 'cjs'
? `module.exports = require('jiti')()('${input}')`
@@ -118,7 +118,7 @@ ${buildEntries.map(entry => `${chalk.bold(entry.path)}
).join('\n')}`)
const usedDependencies = new Set()
- const unusedDependencies = new Set(Object.keys(pkg.dependencies))
+ const unusedDependencies = new Set(Object.keys(pkg.dependencies || {}))
const implicitDependnecies = new Set()
for (const id of usedImports) {
unusedDependencies.delete(id)
diff --git a/tsconfig.json b/tsconfig.json
index edaf2632bf..7e9b960e58 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,6 +2,7 @@
"compilerOptions": {
"esModuleInterop": true,
"target": "ESNext",
+ "module": "ESNext",
"moduleResolution": "Node",
"strict": false,
"allowJs": true,
diff --git a/yarn.lock b/yarn.lock
index 7de448eb29..3983adaf4a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10672,6 +10672,11 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
+untyped@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/untyped/-/untyped-0.2.2.tgz#b8c83d2e8f890cd45108495929bb5574b274fa1a"
+ integrity sha512-AZPhUm/dr/2mnK1mwE67FuV3hbKers34Vp0b8xz26b9JwPg62bvVJGHyWU2rC05acW6tO6OZHfqE5m1J/JjtPg==
+
upath@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b"