mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat: @nuxt/kit
and new config schema (#34)
This commit is contained in:
parent
19650bf1fd
commit
46f771a98b
@ -8,8 +8,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"link": "lerna link",
|
"link": "lerna link",
|
||||||
"nuxt": "jiti ./scripts/nuxt",
|
"nuxt": "jiti ./scripts/nuxt",
|
||||||
"build": "yarn workspaces run build",
|
"build": "yarn workspaces run build --silent",
|
||||||
"stub": "yarn workspaces run stub",
|
"stub": "yarn workspaces run stub --silent",
|
||||||
"play": "yarn nuxt dev playground",
|
"play": "yarn nuxt dev playground",
|
||||||
"lint": "eslint --ext .vue,.ts,.js .",
|
"lint": "eslint --ext .vue,.ts,.js .",
|
||||||
"test": "yarn lint",
|
"test": "yarn lint",
|
||||||
|
32
packages/kit/package.json
Normal file
32
packages/kit/package.json
Normal file
@ -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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
packages/kit/scripts/genconfig.ts
Normal file
19
packages/kit/scripts/genconfig.ts
Normal file
@ -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: '/<dir>/' }
|
||||||
|
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)
|
97
packages/kit/src/config/env.ts
Normal file
97
packages/kit/src/config/env.ts
Normal file
@ -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))
|
||||||
|
}
|
||||||
|
}
|
57
packages/kit/src/config/load.ts
Normal file
57
packages/kit/src/config/load.ts
Normal file
@ -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)
|
||||||
|
}
|
141
packages/kit/src/config/schema/_app.ts
Normal file
141
packages/kit/src/config/schema/_app.ts
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
166
packages/kit/src/config/schema/_common.ts
Normal file
166
packages/kit/src/config/schema/_common.ts
Normal file
@ -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 || {}) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
159
packages/kit/src/config/schema/build.ts
Normal file
159
packages/kit/src/config/schema/build.ts
Normal file
@ -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
|
||||||
|
}
|
4
packages/kit/src/config/schema/cli.ts
Normal file
4
packages/kit/src/config/schema/cli.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
badgeMessages: [],
|
||||||
|
bannerColor: 'green'
|
||||||
|
}
|
29
packages/kit/src/config/schema/generate.ts
Normal file
29
packages/kit/src/config/schema/generate.ts
Normal file
@ -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))) }
|
||||||
|
}
|
||||||
|
}
|
40
packages/kit/src/config/schema/index.ts
Normal file
40
packages/kit/src/config/schema/index.ts
Normal file
@ -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
|
||||||
|
}
|
10
packages/kit/src/config/schema/messages.ts
Normal file
10
packages/kit/src/config/schema/messages.ts
Normal file
@ -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.'
|
||||||
|
}
|
58
packages/kit/src/config/schema/render.ts
Normal file
58
packages/kit/src/config/schema/render.ts
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
packages/kit/src/config/schema/router.ts
Normal file
31
packages/kit/src/config/schema/router.ts
Normal file
@ -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
|
||||||
|
}
|
7
packages/kit/src/config/schema/server.ts
Normal file
7
packages/kit/src/config/schema/server.ts
Normal file
@ -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
|
||||||
|
}
|
2
packages/kit/src/index.ts
Normal file
2
packages/kit/src/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './config/load'
|
||||||
|
export * from './config/env'
|
@ -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<Plugin>
|
|
||||||
vue: {
|
|
||||||
config: Partial<App['config']>
|
|
||||||
}
|
|
||||||
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 extends Record<string, any>> = T & {
|
|
||||||
// pageTransition?: Exclude<T['pageTransition'], string>
|
|
||||||
// layoutTransition?: Exclude<T['layoutTransition'], string>
|
|
||||||
// extensions?: Exclude<T['extensions'], string>
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export function normalizeAppConfig<O extends Configuration>(options: O): asserts options is NormalizedConfiguration<O> {
|
|
||||||
// (options as NormalizedConfiguration<O>).__normalized__ = true
|
|
||||||
|
|
||||||
// // Normalize options
|
|
||||||
// if (options.loading === true) {
|
|
||||||
// delete options.loading
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (options.router && typeof options.router.base === 'string') {
|
|
||||||
// (options as NormalizedConfiguration<O>)._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]
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -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<typeof ignore>[0]
|
|
||||||
type IgnoreInstance = ReturnType<typeof ignore>
|
|
||||||
|
|
||||||
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<T = any> = (this: ModuleThis, moduleOptions: T) => Promise<void> | 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<string, string>
|
|
||||||
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<string | IgnoreInstance>
|
|
||||||
// TODO: remove in Nuxt 3
|
|
||||||
mode: Mode
|
|
||||||
modern?: boolean | 'client' | 'server'
|
|
||||||
modules: NuxtModule[]
|
|
||||||
privateRuntimeConfig: Record<string, any> | ((env: NodeJS.ProcessEnv) => Record<string, any>)
|
|
||||||
publicRuntimeConfig: Record<string, any> | ((env: NodeJS.ProcessEnv) => Record<string, any>)
|
|
||||||
serverMiddleware: Array<ServerMiddleware> | Record<string, express.Handler>
|
|
||||||
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: {}
|
|
||||||
})
|
|
@ -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<TransformOptions, Exclude<keyof TransformOptions, 'presets' | 'plugins'>> {
|
|
||||||
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']>) | 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<string, string>
|
|
||||||
customProperties: Record<string, string>
|
|
||||||
customSelectors: Record<string, string>
|
|
||||||
environmentVariables?: Record<string, string>
|
|
||||||
}
|
|
||||||
|
|
||||||
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<PostcssVariableMap> | ((map: PostcssVariableMap) => Partial<PostcssVariableMap>)
|
|
||||||
features?: {
|
|
||||||
[key: string]: boolean | { [key: string]: any }
|
|
||||||
}
|
|
||||||
importFrom?: string | string[] | Partial<PostcssVariableMap> | (() => Partial<PostcssVariableMap>)
|
|
||||||
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<string, any>
|
|
||||||
}
|
|
||||||
|
|
||||||
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<string, any>,
|
|
||||||
/**
|
|
||||||
* 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<string, any> | false,
|
|
||||||
optimizeCSS: undefined as Record<string, any> | 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 | ((context: WebpackEnv) => 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[]
|
|
||||||
|
|
||||||
})
|
|
@ -1,11 +0,0 @@
|
|||||||
import { Color } from 'chalk'
|
|
||||||
|
|
||||||
export interface CliOptions {
|
|
||||||
badgeMessages: string[]
|
|
||||||
bannerColor: typeof Color
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (): CliOptions => ({
|
|
||||||
badgeMessages: [],
|
|
||||||
bannerColor: 'green'
|
|
||||||
})
|
|
@ -1,45 +0,0 @@
|
|||||||
import { GlobbyOptions } from 'globby'
|
|
||||||
|
|
||||||
type GenerateRoute = string | { route: string, payload: any }
|
|
||||||
|
|
||||||
type GenerateRoutesFunction = () => (Promise<GenerateRoute[]> | 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}"
|
|
||||||
}
|
|
||||||
})
|
|
@ -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<typeof server> | boolean,
|
|
||||||
cli: cli(),
|
|
||||||
generate: generate(),
|
|
||||||
export: undefined as undefined | GenerateOptions,
|
|
||||||
telemetry: undefined as undefined | boolean
|
|
||||||
})
|
|
||||||
|
|
||||||
export type DefaultConfiguration = ReturnType<typeof getDefaultNuxtConfig>
|
|
@ -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.'
|
|
||||||
})
|
|
@ -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
|
|
||||||
})
|
|
@ -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<string, ServePlaceholderHandler | null | false>
|
|
||||||
mimes?: Record<ServePlaceholderHandler, string | false | undefined>
|
|
||||||
noCache?: boolean
|
|
||||||
placeholders?: Record<ServePlaceholderHandler, string | Buffer | false>
|
|
||||||
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<CspPolicyName, string[]>
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,50 +0,0 @@
|
|||||||
import { RouteRecordRaw, RouterScrollBehavior } from 'vue-router'
|
|
||||||
|
|
||||||
type UnionToIntersection<T> = (T extends any ? (k: T) => void : never) extends ((k: infer U) => void) ? U : never
|
|
||||||
type RouteConfig = UnionToIntersection<RouteRecordRaw>
|
|
||||||
|
|
||||||
export interface Route extends Pick<RouteConfig, Exclude<keyof RouteConfig, 'children' | 'component'>> {
|
|
||||||
children?: Route[]
|
|
||||||
chunkName?: string
|
|
||||||
chunkNames?: Record<string, string>
|
|
||||||
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
|
|
||||||
})
|
|
@ -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 }
|
|
||||||
})
|
|
@ -1,3 +0,0 @@
|
|||||||
export { defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
|
|
||||||
export { getNuxtConfig, Configuration, NormalizedConfiguration } from './options'
|
|
||||||
export { loadNuxtConfig } from './load'
|
|
@ -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<string, any>) => Promise<Configuration>) = 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<string, string>, source: Record<string, string> = {}, 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))
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Omit<DefaultConfiguration, keyof InputConfiguration>> { }
|
|
||||||
|
|
||||||
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<keyof typeof loaders> = [
|
|
||||||
'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<typeof normalizeConfig>
|
|
@ -1,39 +0,0 @@
|
|||||||
import { defaultsDeep } from 'lodash'
|
|
||||||
|
|
||||||
export type Optional<T> = {
|
|
||||||
-readonly [K in keyof T]?: T[K] extends Function ? T[K] : T[K] extends RegExp ? T[K] : T[K] extends Promise<any> ? T[K] : T[K] extends Array<infer R> ? Array<R> : Optional<T[K]>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setProp<O extends Record<string, any>, 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<O extends Record<string, any>, K extends keyof O, V> = K extends Array<infer A> ? {
|
|
||||||
[P in keyof O]: K extends P ? O[P] extends Array<infer T> ? Array<A & T> : K | O[P] : O[P]
|
|
||||||
} : O & { [key in K]: V }
|
|
||||||
|
|
||||||
export function overrideProp<O extends Record<string, any>, K extends keyof O, V> (obj: O, key: K, value: V): asserts obj is Override<O, K, V> {
|
|
||||||
(obj as { [key in K]: V })[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteProp<O extends Record<string, any>, K extends string> (obj: O, key: K): asserts obj is Exclude<O, K> {
|
|
||||||
delete obj[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
type MergeArrays<S, T> = S extends Array<infer A1> ? T extends Array<infer A2> ? Array<A1 | A2> : T | Array<A1> : T | S
|
|
||||||
type MergeObjects<S extends Record<string, any>, T extends Record<string, any>> = Omit<S & T, keyof S & keyof T> & {
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
|
||||||
-readonly [K in keyof S & keyof T]: Merge<S[K], T[K]>
|
|
||||||
}
|
|
||||||
type Merge<S, T> = S extends Array<any> ? MergeArrays<S, T> : S extends Function ? S | T : S extends RegExp ? S | T : S extends Promise<any> ? S | T : T extends Function ? S | T : S extends Record<string, any> ? T extends Record<string, any> ? MergeObjects<S, T> : S | T : MergeArrays<S, T>
|
|
||||||
|
|
||||||
// let b: Merged<{ test: string, another: number[] }, { third: () => void, another: string[] }> = {} as any
|
|
||||||
// b.another
|
|
||||||
// let c = b
|
|
||||||
// c.
|
|
||||||
|
|
||||||
// T extends Array<infer A> ? Array<Merged<A, S>> : T
|
|
||||||
|
|
||||||
export function mergeConfigs<Dest extends Record<string, any>, Source extends Record<string, any>> (dest: Dest, source: Source): Merge<Dest, Source> {
|
|
||||||
return defaultsDeep(dest, source)
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
export { default as Module } from './module'
|
export { default as Module } from './module'
|
||||||
export { default as Nuxt } from './nuxt'
|
export { default as Nuxt } from './nuxt'
|
||||||
export { default as Resolver } from './resolver'
|
export { default as Resolver } from './resolver'
|
||||||
export { loadNuxtConfig } from '../config'
|
|
||||||
export { loadNuxt } from './load'
|
export { loadNuxt } from './load'
|
||||||
|
@ -1,53 +1,17 @@
|
|||||||
import { EnvConfig } from '../config/load'
|
import { resolve } from 'path'
|
||||||
import { loadNuxtConfig } from '../config'
|
import { loadNuxtConfig } from '@nuxt/kit'
|
||||||
import Nuxt from './nuxt'
|
import Nuxt from './nuxt'
|
||||||
|
export interface LoadNuxtOptions {
|
||||||
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 LoadOptions {
|
export async function loadNuxt (opts: LoadNuxtOptions) {
|
||||||
for?: keyof typeof OVERRIDES
|
const options = await loadNuxtConfig(opts)
|
||||||
ready?: boolean
|
|
||||||
|
|
||||||
rootDir?: string
|
// Temp
|
||||||
envConfig?: EnvConfig
|
options.appDir = resolve(__dirname, '../app')
|
||||||
configFile?: string
|
options._majorVersion = 3
|
||||||
configContext?: Record<string, any>,
|
|
||||||
configOverrides?: Record<string, any>,
|
|
||||||
createRequire?: (module: NodeJS.Module) => NodeJS.Require
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadNuxt (loadOptions: LoadOptions | LoadOptions['for']) {
|
const nuxt = new Nuxt(options)
|
||||||
// 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()
|
await nuxt.ready()
|
||||||
}
|
|
||||||
|
|
||||||
return nuxt
|
return nuxt
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,8 @@ import fs from 'fs'
|
|||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
|
||||||
import type { NormalizedConfiguration } from '../config'
|
|
||||||
import { chainFn, sequence } from '../utils'
|
import { chainFn, sequence } from '../utils'
|
||||||
|
|
||||||
import type { NuxtModule, ModuleHandler } from '../config/config/_common'
|
|
||||||
import Nuxt from './nuxt'
|
import Nuxt from './nuxt'
|
||||||
|
|
||||||
interface TemplateInput {
|
interface TemplateInput {
|
||||||
@ -24,7 +22,7 @@ export default class ModuleContainer {
|
|||||||
requiredModules: Record<string, {
|
requiredModules: Record<string, {
|
||||||
src: string
|
src: string
|
||||||
options: Record<string, any>
|
options: Record<string, any>
|
||||||
handler: ModuleHandler
|
handler
|
||||||
}>
|
}>
|
||||||
|
|
||||||
constructor (nuxt: Nuxt) {
|
constructor (nuxt: Nuxt) {
|
||||||
@ -127,29 +125,29 @@ export default class ModuleContainer {
|
|||||||
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
||||||
}
|
}
|
||||||
|
|
||||||
addServerMiddleware (middleware: NormalizedConfiguration['serverMiddleware'][number]) {
|
addServerMiddleware (middleware) {
|
||||||
this.options.serverMiddleware.push(middleware)
|
this.options.serverMiddleware.push(middleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
extendBuild (fn: NormalizedConfiguration['build']['extend']) {
|
extendBuild (fn) {
|
||||||
this.options.build.extend = chainFn(this.options.build.extend, 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 = chainFn(
|
||||||
this.options.router.extendRoutes,
|
this.options.router.extendRoutes,
|
||||||
fn
|
fn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
requireModule (moduleOpts: NuxtModule) {
|
requireModule (moduleOpts) {
|
||||||
return this.addModule(moduleOpts)
|
return this.addModule(moduleOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
async addModule (moduleOpts: NuxtModule) {
|
async addModule (moduleOpts) {
|
||||||
let src: string | ModuleHandler
|
let src
|
||||||
let options: Record<string, any>
|
let options: Record<string, any>
|
||||||
let handler: ModuleHandler | ModuleHandler & { meta: { name: string } }
|
let handler
|
||||||
|
|
||||||
// Type 1: String or Function
|
// Type 1: String or Function
|
||||||
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
|
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
|
||||||
@ -224,7 +222,7 @@ export default class ModuleContainer {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.requiredModules[key] = { src, options, handler: handler as ModuleHandler }
|
this.requiredModules[key] = { src, options, handler }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ import isPlainObject from 'lodash/isPlainObject'
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import Hookable from 'hookable'
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
import { getNuxtConfig, Configuration, NormalizedConfiguration } from '../config'
|
|
||||||
|
|
||||||
import { version } from '../../package.json'
|
import { version } from '../../package.json'
|
||||||
|
|
||||||
import ModuleContainer from './module'
|
import ModuleContainer from './module'
|
||||||
@ -25,7 +23,7 @@ export default class Nuxt extends Hookable {
|
|||||||
_initCalled?: boolean
|
_initCalled?: boolean
|
||||||
|
|
||||||
error?: Error & { statusCode?: number, headers?: IncomingHttpHeaders }
|
error?: Error & { statusCode?: number, headers?: IncomingHttpHeaders }
|
||||||
options: NormalizedConfiguration
|
options: any
|
||||||
resolver: Resolver
|
resolver: Resolver
|
||||||
moduleContainer: ModuleContainer
|
moduleContainer: ModuleContainer
|
||||||
server?: any
|
server?: any
|
||||||
@ -33,11 +31,10 @@ export default class Nuxt extends Hookable {
|
|||||||
render?: any['app']
|
render?: any['app']
|
||||||
showReady?: () => void
|
showReady?: () => void
|
||||||
|
|
||||||
constructor (options: Configuration = {}) {
|
constructor (options) {
|
||||||
super(consola)
|
super(consola)
|
||||||
|
|
||||||
// Assign options and apply defaults
|
this.options = options
|
||||||
this.options = getNuxtConfig(options)
|
|
||||||
|
|
||||||
// Create instance of core components
|
// Create instance of core components
|
||||||
this.resolver = new Resolver(this)
|
this.resolver = new Resolver(this)
|
||||||
|
@ -56,7 +56,7 @@ async function main () {
|
|||||||
if (entry.bundle) {
|
if (entry.bundle) {
|
||||||
const input = resolve(ctx.rootDir, entry.input)
|
const input = resolve(ctx.rootDir, entry.input)
|
||||||
stubbed.push(entry.output)
|
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 mkdir(dirname(output)).catch(() => { })
|
||||||
await writeFile(output, entry.format === 'cjs'
|
await writeFile(output, entry.format === 'cjs'
|
||||||
? `module.exports = require('jiti')()('${input}')`
|
? `module.exports = require('jiti')()('${input}')`
|
||||||
@ -118,7 +118,7 @@ ${buildEntries.map(entry => `${chalk.bold(entry.path)}
|
|||||||
).join('\n')}`)
|
).join('\n')}`)
|
||||||
|
|
||||||
const usedDependencies = new Set<string>()
|
const usedDependencies = new Set<string>()
|
||||||
const unusedDependencies = new Set<string>(Object.keys(pkg.dependencies))
|
const unusedDependencies = new Set<string>(Object.keys(pkg.dependencies || {}))
|
||||||
const implicitDependnecies = new Set<string>()
|
const implicitDependnecies = new Set<string>()
|
||||||
for (const id of usedImports) {
|
for (const id of usedImports) {
|
||||||
unusedDependencies.delete(id)
|
unusedDependencies.delete(id)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
@ -10672,6 +10672,11 @@ unset-value@^1.0.0:
|
|||||||
has-value "^0.3.1"
|
has-value "^0.3.1"
|
||||||
isobject "^3.0.0"
|
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:
|
upath@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b"
|
resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b"
|
||||||
|
Loading…
Reference in New Issue
Block a user