From 7ef1a773a300aebf9baa44786a4e2a0b725fce8d Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 26 Oct 2022 10:29:38 +0200 Subject: [PATCH 01/13] initial refactor (wip) --- docs/content/3.api/4.advanced/2.kit.md | 1 - packages/kit/src/module/container.ts | 4 +- packages/kit/src/nitro.ts | 17 - packages/nuxi/src/commands/dev.ts | 8 +- packages/nuxt/src/core/nitro.ts | 27 +- packages/schema/build.config.ts | 16 +- .../schema/src/config/{_adhoc.ts => adhoc.ts} | 8 +- packages/schema/src/config/app.ts | 196 ++++++ packages/schema/src/config/build.ts | 578 +----------------- .../src/config/{_common.ts => common.ts} | 422 +------------ packages/schema/src/config/dev.ts | 38 ++ packages/schema/src/config/experimental.ts | 3 +- packages/schema/src/config/generate.ts | 230 ++----- packages/schema/src/config/index.ts | 64 +- .../src/config/{_internal.ts => internal.ts} | 6 +- packages/schema/src/config/messages.ts | 23 - packages/schema/src/config/nitro.ts | 5 - packages/schema/src/config/postcss.ts | 2 +- packages/schema/src/config/render.ts | 298 --------- packages/schema/src/config/router.ts | 182 +----- packages/schema/src/config/server.ts | 50 -- packages/schema/src/config/typescript.ts | 5 +- packages/schema/src/config/vite.ts | 1 - packages/schema/src/config/webpack.ts | 9 +- packages/schema/src/nuxt2/config.ts | 14 + .../{config/_app.ts => nuxt2/config/app.ts} | 213 +------ packages/schema/src/nuxt2/config/build.ts | 549 +++++++++++++++++ packages/schema/src/{ => nuxt2}/config/cli.ts | 16 +- packages/schema/src/nuxt2/config/common.ts | 260 ++++++++ packages/schema/src/nuxt2/config/generate.ts | 113 ++++ packages/schema/src/nuxt2/config/index.ts | 40 ++ packages/schema/src/nuxt2/config/messages.ts | 22 + packages/schema/src/nuxt2/config/render.ts | 297 +++++++++ packages/schema/src/nuxt2/config/router.ts | 146 +++++ packages/schema/src/nuxt2/config/server.ts | 43 ++ packages/schema/src/nuxt2/hooks.ts | 126 ++++ packages/schema/src/nuxt2/index.ts | 4 + packages/schema/src/types/hooks.ts | 127 +--- packages/schema/src/types/imports.ts | 9 +- packages/vite/src/client.ts | 8 +- packages/vite/src/vite-node.ts | 18 +- 41 files changed, 2047 insertions(+), 2151 deletions(-) rename packages/schema/src/config/{_adhoc.ts => adhoc.ts} (86%) create mode 100644 packages/schema/src/config/app.ts rename packages/schema/src/config/{_common.ts => common.ts} (52%) create mode 100644 packages/schema/src/config/dev.ts rename packages/schema/src/config/{_internal.ts => internal.ts} (84%) delete mode 100644 packages/schema/src/config/messages.ts delete mode 100644 packages/schema/src/config/render.ts delete mode 100644 packages/schema/src/config/server.ts create mode 100644 packages/schema/src/nuxt2/config.ts rename packages/schema/src/{config/_app.ts => nuxt2/config/app.ts} (56%) create mode 100644 packages/schema/src/nuxt2/config/build.ts rename packages/schema/src/{ => nuxt2}/config/cli.ts (54%) create mode 100644 packages/schema/src/nuxt2/config/common.ts create mode 100644 packages/schema/src/nuxt2/config/generate.ts create mode 100644 packages/schema/src/nuxt2/config/index.ts create mode 100644 packages/schema/src/nuxt2/config/messages.ts create mode 100644 packages/schema/src/nuxt2/config/render.ts create mode 100644 packages/schema/src/nuxt2/config/router.ts create mode 100644 packages/schema/src/nuxt2/config/server.ts create mode 100644 packages/schema/src/nuxt2/hooks.ts create mode 100644 packages/schema/src/nuxt2/index.ts diff --git a/docs/content/3.api/4.advanced/2.kit.md b/docs/content/3.api/4.advanced/2.kit.md index d0691cd48a0..cc5fa45ce1f 100644 --- a/docs/content/3.api/4.advanced/2.kit.md +++ b/docs/content/3.api/4.advanced/2.kit.md @@ -74,7 +74,6 @@ description: Nuxt Kit provides composable utilities to help interacting with Nux [source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/nitro.ts) -- ~~`addServerMiddleware(serverMiddleware)`~~ - `addServerHandler (handler)` - `addDevServerHandler (handler)` - `useNitro()` (only usable after `ready` hook) diff --git a/packages/kit/src/module/container.ts b/packages/kit/src/module/container.ts index 5f806f85071..21e2b61107b 100644 --- a/packages/kit/src/module/container.ts +++ b/packages/kit/src/module/container.ts @@ -3,7 +3,6 @@ import type { Nuxt, ModuleContainer } from '@nuxt/schema' import { chainFn } from '../internal/task' import { addTemplate } from '../template' import { addLayout } from '../layout' -import { addServerMiddleware } from '../nitro' import { isNuxt2 } from '../compatibility' import { addPluginTemplate } from '../plugin' import { useNuxt } from '../context' @@ -44,7 +43,8 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer { requireModule, addModule: requireModule, - addServerMiddleware, + // TODO + addServerMiddleware: () => { }, addTemplate (template) { if (typeof template === 'string') { diff --git a/packages/kit/src/nitro.ts b/packages/kit/src/nitro.ts index 8e48265246b..ce88422c5f1 100644 --- a/packages/kit/src/nitro.ts +++ b/packages/kit/src/nitro.ts @@ -1,14 +1,6 @@ -import type { NodeMiddleware } from 'h3' import type { NitroEventHandler, NitroDevEventHandler, Nitro } from 'nitropack' import { useNuxt } from './context' -export interface LegacyServerMiddleware { - route?: string, - path?: string, - handle?: NodeMiddleware | string - handler: NodeMiddleware | string -} - /** * normalize handler object * @@ -22,15 +14,6 @@ function normalizeHandlerMethod (handler: NitroEventHandler) { } } -/** - * Adds a new server middleware to the end of the server middleware array. - * - * @deprecated Use addServerHandler instead - */ -export function addServerMiddleware (middleware: LegacyServerMiddleware) { - useNuxt().options.serverMiddleware.push(middleware) -} - /** * Adds a nitro server handler * diff --git a/packages/nuxi/src/commands/dev.ts b/packages/nuxi/src/commands/dev.ts index 9f6311877bd..b014f1e3046 100644 --- a/packages/nuxi/src/commands/dev.ts +++ b/packages/nuxi/src/commands/dev.ts @@ -92,10 +92,10 @@ export default defineNuxtCommand({ await currentNuxt.hooks.callHook('listen', listener.server, listener) const address = listener.server.address() as AddressInfo - currentNuxt.options.server.url = listener.url - currentNuxt.options.server.port = address.port - currentNuxt.options.server.host = address.address - currentNuxt.options.server.https = listener.https + currentNuxt.options.devServer.url = listener.url + currentNuxt.options.devServer.port = address.port + currentNuxt.options.devServer.host = address.address + currentNuxt.options.devServer.https = listener.https await Promise.all([ writeTypes(currentNuxt).catch(console.error), diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 0fc7dcc1f95..05e70d8de4c 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -21,7 +21,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { debug: nuxt.options.debug, rootDir: nuxt.options.rootDir, workspaceDir: nuxt.options.workspaceDir, - srcDir: nuxt.options.serverDir, + srcDir: nuxt.options.devServerDir, dev: nuxt.options.dev, buildDir: nuxt.options.buildDir, analyze: nuxt.options.build.analyze && { @@ -185,7 +185,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { } else { const distDir = resolve(nuxt.options.rootDir, 'dist') if (!existsSync(distDir)) { - await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => {}) + await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => { }) } } } @@ -206,29 +206,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { } } -async function resolveHandlers (nuxt: Nuxt) { - const handlers: NitroEventHandler[] = [...nuxt.options.serverHandlers] +function resolveHandlers (nuxt: Nuxt) { + const handlers: NitroEventHandler[] = [...nuxt.options.devServerHandlers] const devHandlers: NitroDevEventHandler[] = [...nuxt.options.devServerHandlers] - // Map legacy serverMiddleware to handlers - for (let m of nuxt.options.serverMiddleware) { - if (typeof m === 'string' || typeof m === 'function' /* legacy middleware */) { m = { handler: m } } - const route = m.path || m.route || '/' - const handler = m.handler || m.handle - if (typeof handler !== 'string' || typeof route !== 'string') { - devHandlers.push({ route, handler }) - } else { - delete m.handler - delete m.path - handlers.push({ - ...m, - route, - middleware: true, - handler: await resolvePath(handler) - }) - } - } - return { handlers, devHandlers diff --git a/packages/schema/build.config.ts b/packages/schema/build.config.ts index 82e22e2b494..bac8807fa25 100644 --- a/packages/schema/build.config.ts +++ b/packages/schema/build.config.ts @@ -15,7 +15,21 @@ export default defineBuildConfig({ } } }, - 'src/index' + 'src/index', + // Nuxt 2 + { + input: 'src/nuxt2/config/index', + outDir: 'schema/nuxt2', + name: 'config', + builder: 'untyped', + defaults: { + rootDir: '//', + vite: { + base: '/' + } + } + }, + 'src/nuxt2/index', ], externals: [ // Type imports diff --git a/packages/schema/src/config/_adhoc.ts b/packages/schema/src/config/adhoc.ts similarity index 86% rename from packages/schema/src/config/_adhoc.ts rename to packages/schema/src/config/adhoc.ts index 88a4f949a1e..7d81e8151e1 100644 --- a/packages/schema/src/config/_adhoc.ts +++ b/packages/schema/src/config/adhoc.ts @@ -8,11 +8,8 @@ export default defineUntypedSchema({ * pages, layouts (and other components) without needing to explicitly import them. * * @default {{ dirs: [`~/components`] }} - * @see [Nuxt 3](https://v3.nuxtjs.org/guide/directory-structure/components) and - * [Nuxt 2](https://nuxtjs.org/docs/directory-structure/components/) documentation + * @see https://v3.nuxtjs.org/guide/directory-structure/components * @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']} - * @version 2 - * @version 3 */ components: { $resolve: (val) => { @@ -34,7 +31,6 @@ export default defineUntypedSchema({ * * @see [Nuxt 3 documentation](https://v3.nuxtjs.org/guide/directory-structure/composables) * @type {typeof import('../src/types/imports').ImportsOptions} - * @version 3 */ imports: { global: false, @@ -46,7 +42,6 @@ export default defineUntypedSchema({ * enabled if you have a `pages/` directory in your source folder. * * @type {boolean} - * @version 3 */ pages: undefined, @@ -56,7 +51,6 @@ export default defineUntypedSchema({ * @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. * * @type {boolean} - * @version 3 */ telemetry: undefined }) diff --git a/packages/schema/src/config/app.ts b/packages/schema/src/config/app.ts new file mode 100644 index 00000000000..30a7edf39ec --- /dev/null +++ b/packages/schema/src/config/app.ts @@ -0,0 +1,196 @@ +import { defineUntypedSchema } from 'untyped' +import defu from 'defu' +import type { AppHeadMetaObject } from '../types/meta' + +export default defineUntypedSchema({ + /** + * Vue.js config + */ + vue: { + /** + * Options for the Vue compiler that will be passed at build time. + * @see [documentation](https://vuejs.org/api/application.html#app-config-compileroptions) + * @type {typeof import('@vue/compiler-core').CompilerOptions} + */ + compilerOptions: {} + }, + + /** + * Nuxt App configuration. + */ + app: { + /** + * The base path of your Nuxt application. + * + * This can be set at runtime by setting the NUXT_APP_BASE_URL environment variable. + * @example + * ```bash + * NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs + * ``` + */ + baseURL: { + $resolve: async (val) => val || process.env.NUXT_APP_BASE_URL || '/', + }, + + /** The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. */ + buildAssetsDir: { + $resolve: async (val) => val || process.env.NUXT_APP_BUILD_ASSETS_DIR || '/_nuxt/', + }, + + /** + * An absolute URL to serve the public folder from (production-only). + * + * This can be set to a different value at runtime by setting the `NUXT_APP_CDN_URL` environment variable. + * @example + * ```bash + * NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs + * ``` + */ + cdnURL: { + $resolve: async (val, get) => (await get('dev')) ? '' : (process.env.NUXT_APP_CDN_URL ?? val) || '' + }, + + /** + * Set default configuration for `` on every page. + * + * @example + * ```js + * app: { + * head: { + * meta: [ + * // + * { name: 'viewport', content: 'width=device-width, initial-scale=1' } + * ], + * script: [ + * // + * { src: 'https://awesome-lib.js' } + * ], + * link: [ + * // + * { rel: 'stylesheet', href: 'https://awesome-lib.css' } + * ], + * // please note that this is an area that is likely to change + * style: [ + * // + * { children: ':root { color: red }', type: 'text/css' } + * ], + * noscript: [ + * // + * { children: 'Javascript is required' } + * ] + * } + * } + * ``` + * @type {typeof import('../src/types/config').NuxtAppConfig['head']} + */ + head: { + $resolve: async (val, get) => { + const resolved: Required = defu(val, await get('meta'), { + meta: [], + link: [], + style: [], + script: [], + noscript: [] + }) + + // provides default charset and viewport if not set + if (!resolved.meta.find(m => m.charset)?.charset) { + resolved.meta.unshift({ charset: resolved.charset || 'utf-8' }) + } + if (!resolved.meta.find(m => m.name === 'viewport')?.content) { + resolved.meta.unshift({ name: 'viewport', content: resolved.viewport || 'width=device-width, initial-scale=1' }) + } + + resolved.meta = resolved.meta.filter(Boolean) + resolved.link = resolved.link.filter(Boolean) + resolved.style = resolved.style.filter(Boolean) + resolved.script = resolved.script.filter(Boolean) + resolved.noscript = resolved.noscript.filter(Boolean) + + return resolved + } + }, + + /** + * Default values for layout transitions. + * + * This can be overridden with `definePageMeta` on an individual page. + * Only JSON-serializable values are allowed. + * + * @see https://vuejs.org/api/built-in-components.html#transition + * @type {typeof import('../src/types/config').NuxtAppConfig['layoutTransition']} + */ + layoutTransition: false, + + /** + * Default values for page transitions. + * + * This can be overridden with `definePageMeta` on an individual page. + * Only JSON-serializable values are allowed. + * + * @see https://vuejs.org/api/built-in-components.html#transition + * @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']} + */ + pageTransition: false, + + /** + * Default values for KeepAlive configuration between pages. + * + * This can be overridden with `definePageMeta` on an individual page. + * Only JSON-serializable values are allowed. + * + * @see https://vuejs.org/api/built-in-components.html#keepalive + * @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']} + */ + keepalive: false, + }, + + /** + * An array of nuxt app plugins. + * + * Each plugin can be a string (which can be an absolute or relative path to a file). + * If it ends with `.client` or `.server` then it will be automatically loaded only + * in the appropriate context. + * + * It can also be an object with `src` and `mode` keys. + * + * @example + * ```js + * plugins: [ + * '~/plugins/foo.client.js', // only in client side + * '~/plugins/bar.server.js', // only in server side + * '~/plugins/baz.js', // both client & server + * { src: '~/plugins/both-sides.js' }, + * { src: '~/plugins/client-only.js', mode: 'client' }, // only on client side + * { src: '~/plugins/server-only.js', mode: 'server' } // only on server side + * ] + * ``` + * @type {(typeof import('../src/types/nuxt').NuxtPlugin | string)[]} + */ + plugins: [], + + /** + * You can define the CSS files/modules/libraries you want to set globally + * (included in every page). + * + * Nuxt will automatically guess the file type by its extension and use the + * appropriate pre-processor. You will still need to install the required + * loader if you need to use them. + * + * @example + * ```js + * css: [ + * // Load a Node.js module directly (here it's a Sass file). + * 'bulma', + * // CSS file in the project + * '@/assets/css/main.css', + * // SCSS file in the project + * '@/assets/css/main.scss' + * ] + * ``` + * @type {string[]} + */ + css: { + $resolve: val => (val ?? []).map((c: any) => c.src || c) + } +}) diff --git a/packages/schema/src/config/build.ts b/packages/schema/src/config/build.ts index 275586702f8..1875af8524a 100644 --- a/packages/schema/src/config/build.ts +++ b/packages/schema/src/config/build.ts @@ -1,7 +1,4 @@ import defu from 'defu' -import { join } from 'pathe' -import { isCI, isTest } from 'std-env' -import { normalizeURL, withTrailingSlash } from 'ufo' import { defineUntypedSchema } from 'untyped' export default defineUntypedSchema({ @@ -9,7 +6,6 @@ export default defineUntypedSchema({ * The builder to use for bundling the Vue part of your application. * * @type {'vite' | 'webpack' | { bundle: (nuxt: typeof import('../src/types/nuxt').Nuxt) => Promise }} - * @version 3 */ builder: { $resolve: async (val, get) => { @@ -23,11 +19,11 @@ export default defineUntypedSchema({ return map[val] || val || (await get('vite') === false ? map.webpack : map.vite) } }, + /** * Whether to generate sourcemaps. * * @type {boolean | { server?: boolean, client?: boolean }} - * @version 3 */ sourcemap: { $resolve: async (val, get) => { @@ -40,445 +36,11 @@ export default defineUntypedSchema({ }) }, }, + /** * Shared build configuration. - * @version 2 - * @version 3 */ build: { - /** - * Suppresses most of the build output log. - * - * It is enabled by default when a CI or test environment is detected. - * - * @see [std-env](https://github.com/unjs/std-env) - * @version 2 - * @version 3 - */ - quiet: Boolean(isCI || isTest), - - /** - * Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. - * - * Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - * - * @example - * ```js - * analyze: { - * analyzerMode: 'static' - * } - * ``` - * @type {boolean | typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options | typeof import('rollup-plugin-visualizer').PluginVisualizerOptions} - */ - analyze: { - $resolve: async (val, get) => { - if (val !== true) { - return val ?? false - } - const rootDir = await get('rootDir') - return { - template: 'treemap', - projectRoot: rootDir, - filename: join(rootDir, '.nuxt/stats', '{name}.html') - } - } - }, - - /** - * Enable the profiler in webpackbar. - * - * It is normally enabled by CLI argument `--profile`. - * - * @see [webpackbar](https://github.com/unjs/webpackbar#profile) - * @version 2 - */ - profile: process.argv.includes('--profile'), - - /** - * Enables Common CSS Extraction using - * [Vue Server Renderer guidelines](https://ssr.vuejs.org/guide/css.html). - * - * Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, your CSS will be extracted - * into separate files, usually one per component. This allows caching your CSS and - * JavaScript separately and is worth trying if you have a lot of global or shared CSS. - * - * @example - * ```js - * export default { - * build: { - * extractCSS: true, - * // or - * extractCSS: { - * ignoreOrder: true - * } - * } - * } - * ``` - * - * If you want to extract all your CSS to a single file, there is a workaround for this. - * However, note that it is not recommended to extract everything into a single file. - * Extracting into multiple CSS files is better for caching and preload isolation. It - * can also improve page performance by downloading and resolving only those resources - * that are needed. - * - * @example - * ```js - * export default { - * build: { - * extractCSS: true, - * optimization: { - * splitChunks: { - * cacheGroups: { - * styles: { - * name: 'styles', - * test: /\.(css|vue)$/, - * chunks: 'all', - * enforce: true - * } - * } - * } - * } - * } - * } - * ``` - * @version 2 - */ - extractCSS: false, - - /** - * Enables CSS source map support (defaults to true in development) - * @version 2 - */ - cssSourceMap: { - $resolve: async (val, get) => val ?? (await get('sourcemap.client') || await get('sourcemap.server')) ?? await get('dev') - }, - - /** - * Creates special webpack bundle for SSR renderer. It is normally not necessary to change this value. - * @version 2 - */ - ssr: undefined, - - /** - * Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) when building app with webpack. - * - * @warning This is an unstable feature. - * @version 2 - */ - parallel: { - $resolve: async (val, get) => await get('build.extractCSS') ? false : Boolean(val) - }, - - /** - * Enable caching for [`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#options) - * and [`cache-loader`](https://github.com/webpack-contrib/cache-loader#cache-loader). - * - * @warning This is an unstable feature. - * @version 2 - */ - cache: false, - - /** - * Inline server bundle dependencies. - * - * This mode bundles `node_modules` that are normally preserved as externals in the server build. - * - * @warning Runtime dependencies (modules, `nuxt.config`, server middleware and the static directory) are not bundled. - * This feature only disables use of [webpack-externals](https://webpack.js.org/configuration/externals/) for server-bundle. - * - * @note You can enable standalone bundling by passing `--standalone` via the command line. - * - * @see [context](https://github.com/nuxt/nuxt.js/pull/4661) - * @version 2 - */ - standalone: false, - - /** - * If you are uploading your dist files to a CDN, you can set the publicPath to your CDN. - * - * @note This is only applied in production. - * - * The value of this property at runtime will override the configuration of an app that - * has already been built. - * - * @example - * ```js - * build: { - * publicPath: process.env.PUBLIC_PATH || 'https://cdn.nuxtjs.org' - * } - * ``` - * @version 2 - */ - publicPath: { - $resolve: async (val, get) => val ? withTrailingSlash(normalizeURL(val)) : (await get('app').buildAssetsDir) - }, - - /** - * The polyfill library to load to provide URL and URLSearchParams. - * - * Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)). - * @version 2 - */ - serverURLPolyfill: 'url', - - /** - * Customize bundle filenames. - * - * To understand a bit more about the use of manifests, take a look at [this webpack documentation](https://webpack.js.org/guides/code-splitting/). - * - * @note Be careful when using non-hashed based filenames in production - * as most browsers will cache the asset and not detect the changes on first load. - * - * This example changes fancy chunk names to numerical ids: - * - * @example - * ```js - * filenames: { - * chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js') - * } - * ``` - * @type {Record string)>} - * @version 2 - */ - filenames: { - app: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`, - chunk: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`, - css: ({ isDev }: any) => isDev ? '[name].css' : 'css/[contenthash:7].css', - img: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]', - font: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]', - video: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]' - }, - - /** - * Customize the options of Nuxt's integrated webpack loaders. - * @version 2 - */ - loaders: { - $resolve: async (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(await get('build.cssSourceMap')) - } - } - return val - }, - file: { esModule: false }, - fontUrl: { esModule: false, limit: 1000 }, - imgUrl: { esModule: false, limit: 1000 }, - pugPlain: {}, - vue: { - productionMode: { $resolve: async (val, get) => val ?? !(await get('dev')) }, - transformAssetUrls: { - video: 'src', - source: 'src', - object: 'src', - embed: 'src' - }, - compilerOptions: { $resolve: async (val, get) => val ?? await get('vue.compilerOptions') }, - }, - css: { - importLoaders: 0, - esModule: false - }, - cssModules: { - importLoaders: 0, - esModule: false, - modules: { - localIdentName: '[local]_[hash:base64:5]' - } - }, - less: {}, - sass: { - sassOptions: { - indentedSyntax: true - } - }, - scss: {}, - stylus: {}, - vueStyle: {} - }, - - /** - * @deprecated Use [style-resources-module](https://github.com/nuxt-community/style-resources-module/) - * @version 2 - */ - styleResources: {}, - - /** - * Add webpack plugins. - * - * @example - * ```js - * import webpack from 'webpack' - * import { version } from './package.json' - * // ... - * plugins: [ - * new webpack.DefinePlugin({ - * 'process.VERSION': version - * }) - * ] - * ``` - * @version 2 - */ - plugins: [], - - /** - * Terser plugin options. - * - * Set to false to disable this plugin, or pass an object of options. - * - * @see [terser-webpack-plugin documentation](https://github.com/webpack-contrib/terser-webpack-plugin) - * - * @note Enabling sourcemap will leave `//# sourcemappingURL` linking comment at - * the end of each output file if webpack `config.devtool` is set to `source-map`. - * @version 2 - */ - terser: {}, - - /** - * Enables the [HardSourceWebpackPlugin](https://github.com/mzgoddard/hard-source-webpack-plugin) for improved caching. - * - * @warning unstable - * @version 2 - */ - hardSource: false, - - /** - * Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. - * @version 2 - */ - aggressiveCodeRemoval: false, - - /** - * OptimizeCSSAssets plugin options. - * - * Defaults to true when `extractCSS` is enabled. - * - * @see [optimize-css-assets-webpack-plugin documentation](https://github.com/NMFR/optimize-css-assets-webpack-plugin). - * @version 2 - */ - optimizeCSS: { - $resolve: async (val, get) => val ?? (await get('build.extractCSS') ? {} : false) - }, - - /** - * Configure [webpack optimization](https://webpack.js.org/configuration/optimization/). - * @version 2 - */ - optimization: { - runtimeChunk: 'single', - /** Set minimize to false to disable all minimizers. (It is disabled in development by default) */ - minimize: { - $resolve: async (val, get) => val ?? !(await get('dev')) - }, - /** You can set minimizer to a customized array of plugins. */ - minimizer: undefined, - splitChunks: { - chunks: 'all', - automaticNameDelimiter: '/', - cacheGroups: {} - } - }, - - /** - * Whether to split code for `layout`, `pages` and `commons` chunks. - * - * Commons libs include `vue`, `vue-loader`, `vue-router`, `vuex`, etc. - * @version 2 - */ - splitChunks: { - layouts: false, - pages: true, - commons: true - }, - - /** - * Nuxt will automatically detect the current version of `core-js` in your project (`'auto'`), - * or you can specify which version you want to use (`2` or `3`). - * @version 2 - */ - corejs: 'auto', - - /** - * Customize your Babel configuration. - * - * See [babel-loader options](https://github.com/babel/babel-loader#options) and - * [babel options](https://babeljs.io/docs/en/options). - * - * @note `.babelrc` is ignored by default. - * @version 2 - */ - babel: { - configFile: false, - babelrc: false, - /** - * An array of Babel plugins to load, or a function that takes webpack context and returns - * an array of Babel plugins. - * - * For more information see [Babel plugins options](https://babeljs.io/docs/en/options#plugins) - * and [babel-loader options](https://github.com/babel/babel-loader#options). - */ - plugins: [], - /** - * The Babel presets to be applied. - * - * @note The presets configured here will be applied to both the client and the server - * build. The target will be set by Nuxt accordingly (client/server). If you want to configure - * the preset differently for the client or the server build, please use presets as a function. - * - * @warning It is highly recommended to use the default preset instead customizing. - * - * @example - * ```js - * export default { - * build: { - * babel: { - * presets({ isServer }, [ preset, options ]) { - * // change options directly - * options.targets = isServer ? '...' : '...' - * options.corejs = '...' - * // return nothing - * } - * } - * } - * } - * ``` - * - * @example - * ```js - * export default { - * build: { - * babel: { - * presets({ isServer }, [preset, options]) { - * return [ - * [ - * preset, - * { - * targets: isServer ? '...' : '...', - * ...options - * } - * ], - * [ - * // Other presets - * ] - * ] - * } - * } - * } - * } - * ``` - */ - presets: {}, - cacheDirectory: { - $resolve: async (val, get) => val ?? (await get('dev')) - } - }, - /** * If you want to transpile specific dependencies with Babel, you can add them here. * Each item in transpile can be a package name, a function, a string or regex object matching the @@ -490,80 +52,12 @@ export default defineUntypedSchema({ * ```js transpile: [({ isLegacy }) => isLegacy && 'ky'] * ``` - * @version 2 - * @version 3 * @type {Array} */ transpile: { $resolve: val => [].concat(val).filter(Boolean) }, - /** - * Customize PostCSS Loader plugins. - * Sames options as https://github.com/webpack-contrib/postcss-loader#options - * @version 2 - */ - postcss: { - execute: undefined, - postcssOptions: { - $resolve: async (val, get) => { - // Ensure we return the same object in `build.postcss.postcssOptions as `postcss` - // so modules which modify the configuration continue to work. - const postcssOptions = await get('postcss') - Object.assign(postcssOptions, defu(postcssOptions, val)) - return postcssOptions - } - }, - sourcemap: undefined, - implementation: undefined, - order: '' - }, - - /** @version 2 */ - html: { - /** - * Configuration for the html-minifier plugin used to minify HTML files created - * during the build process (will be applied for all modes). - * - * @warning If you make changes, they won't be merged with the defaults! - * - * @example - * ```js - * export default { - * html: { - * minify: { - * collapseBooleanAttributes: true, - * decodeEntities: true, - * minifyCSS: true, - * minifyJS: true, - * processConditionalComments: true, - * removeEmptyAttributes: true, - * removeRedundantAttributes: true, - * trimCustomFragments: true, - * useShortDoctype: true - * } - * } - * } - * ``` - */ - minify: { - collapseBooleanAttributes: true, - decodeEntities: true, - minifyCSS: true, - minifyJS: true, - processConditionalComments: true, - removeEmptyAttributes: true, - removeRedundantAttributes: true, - trimCustomFragments: true, - useShortDoctype: true - } - }, - - /** - * Allows setting a different app template (other than `@nuxt/vue-app`) - * @version 2 - */ - template: undefined, /** * You can provide your own templates which will be rendered based * on Nuxt configuration. This feature is specially useful for using with modules. @@ -583,75 +77,7 @@ export default defineUntypedSchema({ * } * ] * ``` - * @version 2 - * @version 3 */ templates: [], - - /** - * You can provide your custom files to watch and regenerate after changes. - * - * This feature is especially useful for using with modules. - * - * @example - * ```js - watch: ['~/.nuxt/support.js'] - * ``` - * @version 2 - */ - watch: [], - /** - * See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. - * @version 2 - */ - devMiddleware: { - stats: 'none' - }, - /** - * See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options. - * @version 2 - */ - hotMiddleware: {}, - - /** @version 2 */ - vendor: { - $meta: { - deprecated: 'vendor has been deprecated since nuxt 2' - } - }, - - /** - * Set to `'none'` or `false` to disable stats printing out after a build. - * @version 2 - */ - stats: { - $resolve: async (val, get) => (val === 'none' || (await get('build.quiet'))) ? false : val, - excludeAssets: [ - /.map$/, - /index\..+\.html$/, - /vue-ssr-(client|modern)-manifest.json/ - ] - }, - /** - * Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). - * @version 2 - */ - friendlyErrors: true, - /** - * Additional extensions (beyond `['vue', 'js']` to support in `pages/`, `layouts/`, `middleware/`, etc.) - * @version 2 - */ - additionalExtensions: [], - /** - * Filters to hide build warnings. - * @version 2 - */ - warningIgnoreFilters: [], - - /** - * Set to true to scan files within symlinks in the build (such as within `pages/`). - * @version 2 - */ - followSymlinks: false } }) diff --git a/packages/schema/src/config/_common.ts b/packages/schema/src/config/common.ts similarity index 52% rename from packages/schema/src/config/_common.ts rename to packages/schema/src/config/common.ts index 2aa4b4d882c..6823cb803f2 100644 --- a/packages/schema/src/config/_common.ts +++ b/packages/schema/src/config/common.ts @@ -1,15 +1,10 @@ +import { defineUntypedSchema } from 'untyped' import { join, resolve } from 'pathe' import { isDebug, isDevelopment } from 'std-env' -import createRequire from 'create-require' -import { pascalCase } from 'scule' -import jiti from 'jiti' import defu from 'defu' import { findWorkspaceDir } from 'pkg-types' - import { RuntimeConfig } from '../types/config' -import { defineUntypedSchema } from 'untyped' - export default defineUntypedSchema({ /** * Extend project from multiple local or remote sources. @@ -20,7 +15,6 @@ export default defineUntypedSchema({ * * @type {string|string[]} * - * @version 3 */ extends: null, @@ -33,7 +27,6 @@ export default defineUntypedSchema({ * * @type {string} * - * @version 3 */ theme: null, @@ -45,8 +38,6 @@ export default defineUntypedSchema({ * current/working directory. * * It is normally not needed to configure this option. - * @version 2 - * @version 3 */ rootDir: { $resolve: val => typeof val === 'string' ? resolve(val) : process.cwd() @@ -59,7 +50,6 @@ export default defineUntypedSchema({ * your workspace directory automatically, but you can override it here. * * It is normally not needed to configure this option. - * @version 3 */ workspaceDir: { $resolve: async (val, get) => val ? resolve(await get('rootDir'), val) : await findWorkspaceDir(await get('rootDir')).catch(() => get('rootDir')) @@ -93,8 +83,6 @@ export default defineUntypedSchema({ * ------| store/ * ------| server/ * ``` - * @version 2 - * @version 3 */ srcDir: { $resolve: async (val, get) => resolve(await get('rootDir'), val || '.') @@ -106,7 +94,6 @@ export default defineUntypedSchema({ * * If a relative path is specified, it will be relative to your `rootDir`. * - * @version 3 */ serverDir: { $resolve: async (val, get) => resolve(await get('rootDir'), val || resolve(await get('srcDir'), 'server')) @@ -124,25 +111,43 @@ export default defineUntypedSchema({ * buildDir: 'nuxt-build' * } * ``` - * @version 2 - * @version 3 */ buildDir: { $resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt') }, + /** + * Used to set the modules directories for path resolving (for example, webpack's + * `resolveLoading`, `nodeExternals` and `postcss`). + * + * The configuration path is relative to `options.rootDir` (default is current working directory). + * + * Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. + * + * @example + * ```js + * export default { + * modulesDir: ['../../node_modules'] + * } + * ``` + */ + modulesDir: { + $default: ['node_modules'], + $resolve: async (val, get) => [ + ...await Promise.all(val.map(async (dir: string) => resolve(await get('rootDir'), dir))), + resolve(process.cwd(), 'node_modules') + ] + }, + /** * Whether Nuxt is running in development mode. * * Normally, you should not need to set this. - * @version 2 - * @version 3 */ dev: Boolean(isDevelopment), /** * Whether your app is being unit tested. - * @version 2 */ test: Boolean(isDevelopment), @@ -152,118 +157,20 @@ export default defineUntypedSchema({ * At the moment, it prints out hook names and timings on the server, and * logs hook arguments as well in the browser. * - * @version 2 - * @version 3 */ debug: { $resolve: async (val, get) => val ?? isDebug }, - /** - * The `env` property defines environment variables that should be available - * throughout your app (server- and client-side). They can be assigned using - * server-side environment variables. - * - * @note Nuxt uses webpack's `definePlugin` to define these environment variables. - * This means that the actual `process` or `process.env` from Node.js is neither - * available nor defined. Each of the `env` properties defined here is individually - * mapped to `process.env.xxxx` and converted during compilation. - * - * @note Environment variables starting with `NUXT_ENV_` are automatically injected - * into the process environment. - * - * @version 2 - */ - env: { - $default: {}, - $resolve: (val) => { - val = { ...val } - for (const key in process.env) { - if (key.startsWith('NUXT_ENV_')) { - val[key] = process.env[key] - } - } - return val - } - }, - - /** - * Set the method Nuxt uses to require modules, such as loading `nuxt.config`, server - * middleware, and so on - defaulting to `jiti` (which has support for TypeScript and ESM syntax). - * - * @see [jiti](https://github.com/unjs/jiti) - * @type {'jiti' | 'native' | ((p: string | { filename: string }) => NodeRequire)} - * @version 2 - */ - createRequire: { - $resolve: (val: any) => { - val = process.env.NUXT_CREATE_REQUIRE || val || - // @ts-expect-error global type - (typeof globalThis.jest !== 'undefined' ? 'native' : 'jiti') - if (val === 'jiti') { - return (p: string | { filename: string }) => jiti(typeof p === 'string' ? p : p.filename, { esmResolve: true }) - } - if (val === 'native') { - return (p: string | { filename: string }) => createRequire(typeof p === 'string' ? p : p.filename) - } - return val - } - }, - - /** - * Whether your Nuxt app should be built to be served by the Nuxt server (`server`) - * or as static HTML files suitable for a CDN or other static file server (`static`). - * - * This is unrelated to `ssr`. - * @type {'server' | 'static'} - * @version 2 - */ - target: { - $resolve: val => ['server', 'static'].includes(val) ? val : 'server' - }, - /** * Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time. * If set to `false` and combined with `static` target, generated pages will simply display * a loading screen with no content. - * @version 2 - * @version 3 */ ssr: { $resolve: (val) => val ?? true, }, - /** - * @deprecated use `ssr` option - */ - mode: { - $resolve: async (val, get) => val || ((await get('ssr')) ? 'spa' : 'universal'), - $schema: { deprecated: '`mode` option is deprecated' } - }, - - /** - * Whether to produce a separate modern build targeting browsers that support ES modules. - * - * Set to `'server'` to enable server mode, where the Nuxt server checks - * browser version based on the user agent and serves the correct bundle. - * - * Set to `'client'` to serve both the modern bundle with ` - * { src: 'https://awesome-lib.js' } - * ], - * link: [ - * // - * { rel: 'stylesheet', href: 'https://awesome-lib.css' } - * ], - * // please note that this is an area that is likely to change - * style: [ - * // - * { children: ':root { color: red }', type: 'text/css' } - * ], - * noscript: [ - * // - * { children: 'Javascript is required' } - * ] - * } - * } - * ``` - * @type {typeof import('../src/types/config').NuxtAppConfig['head']} - * @version 3 - */ - head: { - $resolve: async (val, get) => { - const resolved: Required = defu(val, await get('meta'), { - meta: [], - link: [], - style: [], - script: [], - noscript: [] - }) - - // provides default charset and viewport if not set - if (!resolved.meta.find(m => m.charset)?.charset) { - resolved.meta.unshift({ charset: resolved.charset || 'utf-8' }) - } - if (!resolved.meta.find(m => m.name === 'viewport')?.content) { - resolved.meta.unshift({ name: 'viewport', content: resolved.viewport || 'width=device-width, initial-scale=1' }) - } - - resolved.meta = resolved.meta.filter(Boolean) - resolved.link = resolved.link.filter(Boolean) - resolved.style = resolved.style.filter(Boolean) - resolved.script = resolved.script.filter(Boolean) - resolved.noscript = resolved.noscript.filter(Boolean) - - return resolved - } - }, - /** - * Default values for layout transitions. - * - * This can be overridden with `definePageMeta` on an individual page. - * Only JSON-serializable values are allowed. - * - * @see https://vuejs.org/api/built-in-components.html#transition - * @type {typeof import('../src/types/config').NuxtAppConfig['layoutTransition']} - */ - layoutTransition: false, - /** - * Default values for page transitions. - * - * This can be overridden with `definePageMeta` on an individual page. - * Only JSON-serializable values are allowed. - * - * @see https://vuejs.org/api/built-in-components.html#transition - * @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']} - */ - pageTransition: false, - /** - * Default values for KeepAlive configuration between pages. - * - * This can be overridden with `definePageMeta` on an individual page. - * Only JSON-serializable values are allowed. - * - * @see https://vuejs.org/api/built-in-components.html#keepalive - * @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']} - */ - keepalive: false, }, + /** * The path to an HTML template file for rendering Nuxt responses. * Uses `/app.html` if it exists, or the Nuxt's default template if not. @@ -187,7 +47,6 @@ export default defineUntypedSchema({ * * * ``` - * @version 2 */ appTemplatePath: { $resolve: async (val, get) => { @@ -205,7 +64,6 @@ export default defineUntypedSchema({ * Enable or disable Vuex store. * * By default, it is enabled if there is a `store/` directory. - * @version 2 */ store: { $resolve: async (val, get) => val !== false && @@ -219,7 +77,6 @@ export default defineUntypedSchema({ * * @see [documentation](https://vue-meta.nuxtjs.org/api/#plugin-options). * @type {typeof import('vue-meta').VueMetaOptions} - * @version 2 */ vueMeta: null, @@ -228,7 +85,6 @@ export default defineUntypedSchema({ * * @see [documentation](https://vue-meta.nuxtjs.org/api/#metainfo-properties) for specifics. * @type {typeof import('vue-meta').MetaInfo} - * @version 2 */ head: { /** Each item in the array maps to a newly-created `` element, where object properties map to attributes. */ @@ -243,7 +99,6 @@ export default defineUntypedSchema({ /** * @type {typeof import('../src/types/meta').AppHeadMetaObject} - * @version 3 * @deprecated - use `head` instead */ meta: { @@ -255,7 +110,6 @@ export default defineUntypedSchema({ /** * Configuration for the Nuxt `fetch()` hook. - * @version 2 */ fetch: { /** Whether to enable `fetch()` on the server. */ @@ -264,73 +118,19 @@ export default defineUntypedSchema({ client: true }, - /** - * An array of nuxt app plugins. - * - * Each plugin can be a string (which can be an absolute or relative path to a file). - * If it ends with `.client` or `.server` then it will be automatically loaded only - * in the appropriate context. - * - * It can also be an object with `src` and `mode` keys. - * - * @example - * ```js - * plugins: [ - * '~/plugins/foo.client.js', // only in client side - * '~/plugins/bar.server.js', // only in server side - * '~/plugins/baz.js', // both client & server - * { src: '~/plugins/both-sides.js' }, - * { src: '~/plugins/client-only.js', mode: 'client' }, // only on client side - * { src: '~/plugins/server-only.js', mode: 'server' } // only on server side - * ] - * ``` - * @type {(typeof import('../src/types/nuxt').NuxtPlugin | string)[]} - * @version 2 - */ - plugins: [], - /** * You may want to extend plugins or change their order. For this, you can pass * a function using `extendPlugins`. It accepts an array of plugin objects and * should return an array of plugin objects. * @type {(plugins: Array<{ src: string, mode?: 'client' | 'server' }>) => Array<{ src: string, mode?: 'client' | 'server' }>} - * @version 2 */ extendPlugins: null, - /** - * You can define the CSS files/modules/libraries you want to set globally - * (included in every page). - * - * Nuxt will automatically guess the file type by its extension and use the - * appropriate pre-processor. You will still need to install the required - * loader if you need to use them. - * - * @example - * ```js - * css: [ - * // Load a Node.js module directly (here it's a Sass file). - * 'bulma', - * // CSS file in the project - * '@/assets/css/main.css', - * // SCSS file in the project - * '@/assets/css/main.scss' - * ] - * ``` - * @type {string[]} - * @version 2 - * @version 3 - */ - css: { - $resolve: val => (val ?? []).map((c: any) => c.src || c) - }, - /** * An object where each key name maps to a path to a layout .vue file. * * Normally, there is no need to configure this directly. * @type {Record} - * @version 2 */ layouts: {}, @@ -339,7 +139,6 @@ export default defineUntypedSchema({ * * Normally, there is no need to configure this directly. * @type {string} - * @version 2 */ ErrorPage: null, @@ -347,7 +146,6 @@ export default defineUntypedSchema({ * Configure the Nuxt loading progress bar component that's shown between * routes. Set to `false` to disable. You can also customize it or create * your own component. - * @version 2 */ loading: { /** CSS color of the progress bar. */ @@ -384,7 +182,6 @@ export default defineUntypedSchema({ * configuration. The name can refer to an indicator from [SpinKit](https://tobiasahlin.com/spinkit/) * or a path to an HTML template of the indicator source code (in this case, all the * other options will be passed to the template). - * @version 2 */ loadingIndicator: { $resolve: async (val, get) => { @@ -408,7 +205,6 @@ export default defineUntypedSchema({ * * @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html) * @see [vue@3 documentation](https://vuejs.org/guide/built-ins/transition-group.html#enter-leave-transitions) - * @version 2 */ pageTransition: { $resolve: async (val, get) => { @@ -431,8 +227,6 @@ export default defineUntypedSchema({ * to the `` component that will wrap your layouts. * * @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html) - * @see [vue@3 documentation](https://vuejs.org/guide/built-ins/transition-group.html#enter-leave-transitions) - * @version 2 */ layoutTransition: { $resolve: val => { @@ -446,7 +240,6 @@ export default defineUntypedSchema({ /** * You can disable specific Nuxt features that you do not want. - * @version 2 */ features: { /** Set to false to disable Nuxt vuex integration */ diff --git a/packages/schema/src/nuxt2/config/build.ts b/packages/schema/src/nuxt2/config/build.ts new file mode 100644 index 00000000000..c1ade01caa2 --- /dev/null +++ b/packages/schema/src/nuxt2/config/build.ts @@ -0,0 +1,549 @@ +import { defineUntypedSchema } from 'untyped' +import defu from 'defu' +import { join } from 'pathe' +import { isCI, isTest } from 'std-env' +import { normalizeURL, withTrailingSlash } from 'ufo' + +/** + * Shared build configuration. + */ +export default defineUntypedSchema({ + build: { + /** + * Suppresses most of the build output log. + * + * It is enabled by default when a CI or test environment is detected. + * + * @see [std-env](https://github.com/unjs/std-env) + */ + quiet: Boolean(isCI || isTest), + + /** + * Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. + * + * Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). + * + * @example + * ```js + * analyze: { + * analyzerMode: 'static' + * } + * ``` + * @type {boolean | typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options | typeof import('rollup-plugin-visualizer').PluginVisualizerOptions} + * + */ + analyze: { + $resolve: async (val, get) => { + if (val !== true) { + return val ?? false + } + const rootDir = await get('rootDir') + return { + template: 'treemap', + projectRoot: rootDir, + filename: join(rootDir, '.nuxt/stats', '{name}.html') + } + } + }, + + /** + * Enable the profiler in webpackbar. + * + * It is normally enabled by CLI argument `--profile`. + * + * @see [webpackbar](https://github.com/unjs/webpackbar#profile) + */ + profile: process.argv.includes('--profile'), + + /** + * Enables Common CSS Extraction using + * [Vue Server Renderer guidelines](https://ssr.vuejs.org/guide/css.html). + * + * Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, your CSS will be extracted + * into separate files, usually one per component. This allows caching your CSS and + * JavaScript separately and is worth trying if you have a lot of global or shared CSS. + * + * @example + * ```js + * export default { + * build: { + * extractCSS: true, + * // or + * extractCSS: { + * ignoreOrder: true + * } + * } + * } + * ``` + * + * If you want to extract all your CSS to a single file, there is a workaround for this. + * However, note that it is not recommended to extract everything into a single file. + * Extracting into multiple CSS files is better for caching and preload isolation. It + * can also improve page performance by downloading and resolving only those resources + * that are needed. + * + * @example + * ```js + * export default { + * build: { + * extractCSS: true, + * optimization: { + * splitChunks: { + * cacheGroups: { + * styles: { + * name: 'styles', + * test: /\.(css|vue)$/, + * chunks: 'all', + * enforce: true + * } + * } + * } + * } + * } + * } + * ``` + */ + extractCSS: false, + + /** + * Enables CSS source map support (defaults to true in development) + */ + cssSourceMap: { + $resolve: async (val, get) => val ?? (await get('sourcemap.client') || await get('sourcemap.server')) ?? await get('dev') + }, + + /** + * Creates special webpack bundle for SSR renderer. It is normally not necessary to change this value. + */ + ssr: undefined, + + /** + * Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) when building app with webpack. + * + * @warning This is an unstable feature. + */ + parallel: { + $resolve: async (val, get) => await get('build.extractCSS') ? false : Boolean(val) + }, + + /** + * Enable caching for [`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#options) + * and [`cache-loader`](https://github.com/webpack-contrib/cache-loader#cache-loader). + * + * @warning This is an unstable feature. + */ + cache: false, + + /** + * Inline server bundle dependencies. + * + * This mode bundles `node_modules` that are normally preserved as externals in the server build. + * + * @warning Runtime dependencies (modules, `nuxt.config`, server middleware and the static directory) are not bundled. + * This feature only disables use of [webpack-externals](https://webpack.js.org/configuration/externals/) for server-bundle. + * + * @note You can enable standalone bundling by passing `--standalone` via the command line. + * + * @see [context](https://github.com/nuxt/nuxt.js/pull/4661) + */ + standalone: false, + + /** + * If you are uploading your dist files to a CDN, you can set the publicPath to your CDN. + * + * @note This is only applied in production. + * + * The value of this property at runtime will override the configuration of an app that + * has already been built. + * + * @example + * ```js + * build: { + * publicPath: process.env.PUBLIC_PATH || 'https://cdn.nuxtjs.org' + * } + * ``` + */ + publicPath: { + $resolve: async (val, get) => val ? withTrailingSlash(normalizeURL(val)) : (await get('app').buildAssetsDir) + }, + + /** + * The polyfill library to load to provide URL and URLSearchParams. + * + * Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)). + */ + serverURLPolyfill: 'url', + + /** + * Customize bundle filenames. + * + * To understand a bit more about the use of manifests, take a look at [this webpack documentation](https://webpack.js.org/guides/code-splitting/). + * + * @note Be careful when using non-hashed based filenames in production + * as most browsers will cache the asset and not detect the changes on first load. + * + * This example changes fancy chunk names to numerical ids: + * + * @example + * ```js + * filenames: { + * chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js') + * } + * ``` + * @type {Record string)>} + */ + filenames: { + app: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`, + chunk: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`, + css: ({ isDev }: any) => isDev ? '[name].css' : 'css/[contenthash:7].css', + img: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]', + font: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]', + video: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]' + }, + + /** + * Customize the options of Nuxt's integrated webpack loaders. + */ + loaders: { + $resolve: async (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(await get('build.cssSourceMap')) + } + } + return val + }, + file: { esModule: false }, + fontUrl: { esModule: false, limit: 1000 }, + imgUrl: { esModule: false, limit: 1000 }, + pugPlain: {}, + vue: { + productionMode: { $resolve: async (val, get) => val ?? !(await get('dev')) }, + transformAssetUrls: { + video: 'src', + source: 'src', + object: 'src', + embed: 'src' + }, + compilerOptions: { $resolve: async (val, get) => val ?? await get('vue.compilerOptions') }, + }, + css: { + importLoaders: 0, + esModule: false + }, + cssModules: { + importLoaders: 0, + esModule: false, + modules: { + localIdentName: '[local]_[hash:base64:5]' + } + }, + less: {}, + sass: { + sassOptions: { + indentedSyntax: true + } + }, + scss: {}, + stylus: {}, + vueStyle: {} + }, + + /** + * @deprecated Use [style-resources-module](https://github.com/nuxt-community/style-resources-module/) + */ + styleResources: {}, + + /** + * Add webpack plugins. + * + * @example + * ```js + * import webpack from 'webpack' + * import { version } from './package.json' + * // ... + * plugins: [ + * new webpack.DefinePlugin({ + * 'process.VERSION': version + * }) + * ] + * ``` + */ + plugins: [], + + /** + * Terser plugin options. + * + * Set to false to disable this plugin, or pass an object of options. + * + * @see [terser-webpack-plugin documentation](https://github.com/webpack-contrib/terser-webpack-plugin) + * + * @note Enabling sourcemap will leave `//# sourcemappingURL` linking comment at + * the end of each output file if webpack `config.devtool` is set to `source-map`. + */ + terser: {}, + + /** + * Enables the [HardSourceWebpackPlugin](https://github.com/mzgoddard/hard-source-webpack-plugin) for improved caching. + * + * @warning unstable + */ + hardSource: false, + + /** + * Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. + */ + aggressiveCodeRemoval: false, + + /** + * OptimizeCSSAssets plugin options. + * + * Defaults to true when `extractCSS` is enabled. + * + * @see [optimize-css-assets-webpack-plugin documentation](https://github.com/NMFR/optimize-css-assets-webpack-plugin). + */ + optimizeCSS: { + $resolve: async (val, get) => val ?? (await get('build.extractCSS') ? {} : false) + }, + + /** + * Configure [webpack optimization](https://webpack.js.org/configuration/optimization/). + */ + optimization: { + runtimeChunk: 'single', + /** Set minimize to false to disable all minimizers. (It is disabled in development by default) */ + minimize: { + $resolve: async (val, get) => val ?? !(await get('dev')) + }, + /** You can set minimizer to a customized array of plugins. */ + minimizer: undefined, + splitChunks: { + chunks: 'all', + automaticNameDelimiter: '/', + cacheGroups: {} + } + }, + + /** + * Whether to split code for `layout`, `pages` and `commons` chunks. + * + * Commons libs include `vue`, `vue-loader`, `vue-router`, `vuex`, etc. + */ + splitChunks: { + layouts: false, + pages: true, + commons: true + }, + + /** + * Nuxt will automatically detect the current version of `core-js` in your project (`'auto'`), + * or you can specify which version you want to use (`2` or `3`). + */ + corejs: 'auto', + + /** + * Customize your Babel configuration. + * + * See [babel-loader options](https://github.com/babel/babel-loader#options) and + * [babel options](https://babeljs.io/docs/en/options). + * + * @note `.babelrc` is ignored by default. + */ + babel: { + configFile: false, + babelrc: false, + /** + * An array of Babel plugins to load, or a function that takes webpack context and returns + * an array of Babel plugins. + * + * For more information see [Babel plugins options](https://babeljs.io/docs/en/options#plugins) + * and [babel-loader options](https://github.com/babel/babel-loader#options). + */ + plugins: [], + /** + * The Babel presets to be applied. + * + * @note The presets configured here will be applied to both the client and the server + * build. The target will be set by Nuxt accordingly (client/server). If you want to configure + * the preset differently for the client or the server build, please use presets as a function. + * + * @warning It is highly recommended to use the default preset instead customizing. + * + * @example + * ```js + * export default { + * build: { + * babel: { + * presets({ isServer }, [ preset, options ]) { + * // change options directly + * options.targets = isServer ? '...' : '...' + * options.corejs = '...' + * // return nothing + * } + * } + * } + * } + * ``` + * + * @example + * ```js + * export default { + * build: { + * babel: { + * presets({ isServer }, [preset, options]) { + * return [ + * [ + * preset, + * { + * targets: isServer ? '...' : '...', + * ...options + * } + * ], + * [ + * // Other presets + * ] + * ] + * } + * } + * } + * } + * ``` + */ + presets: {}, + cacheDirectory: { + $resolve: async (val, get) => val ?? (await get('dev')) + } + }, + + /** + * Customize PostCSS Loader plugins. + * Sames options as https://github.com/webpack-contrib/postcss-loader#options + */ + postcss: { + execute: undefined, + postcssOptions: { + $resolve: async (val, get) => { + // Ensure we return the same object in `build.postcss.postcssOptions as `postcss` + // so modules which modify the configuration continue to work. + const postcssOptions = await get('postcss') + Object.assign(postcssOptions, defu(postcssOptions, val)) + return postcssOptions + } + }, + sourcemap: undefined, + implementation: undefined, + order: '' + }, + + html: { + /** + * Configuration for the html-minifier plugin used to minify HTML files created + * during the build process (will be applied for all modes). + * + * @warning If you make changes, they won't be merged with the defaults! + * + * @example + * ```js + * export default { + * html: { + * minify: { + * collapseBooleanAttributes: true, + * decodeEntities: true, + * minifyCSS: true, + * minifyJS: true, + * processConditionalComments: true, + * removeEmptyAttributes: true, + * removeRedundantAttributes: true, + * trimCustomFragments: true, + * useShortDoctype: true + * } + * } + * } + * ``` + */ + minify: { + collapseBooleanAttributes: true, + decodeEntities: true, + minifyCSS: true, + minifyJS: true, + processConditionalComments: true, + removeEmptyAttributes: true, + removeRedundantAttributes: true, + trimCustomFragments: true, + useShortDoctype: true + } + }, + + /** + * Allows setting a different app template (other than `@nuxt/vue-app`) + */ + template: undefined, + + /** + * You can provide your custom files to watch and regenerate after changes. + * + * This feature is especially useful for using with modules. + * + * @example + * ```js + watch: ['~/.nuxt/support.js'] + * ``` + */ + watch: [], + + /** + * See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. + */ + devMiddleware: { + stats: 'none' + }, + + /** + * See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options. + */ + hotMiddleware: {}, + + vendor: { + $meta: { + deprecated: 'vendor has been deprecated since nuxt 2' + } + }, + + /** + * Set to `'none'` or `false` to disable stats printing out after a build. + */ + stats: { + $resolve: async (val, get) => (val === 'none' || (await get('build.quiet'))) ? false : val, + excludeAssets: [ + /.map$/, + /index\..+\.html$/, + /vue-ssr-(client|modern)-manifest.json/ + ] + }, + + /** + * Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). + */ + friendlyErrors: true, + + /** + * Additional extensions (beyond `['vue', 'js']` to support in `pages/`, `layouts/`, `middleware/`, etc.) + */ + additionalExtensions: [], + + /** + * Filters to hide build warnings. + */ + warningIgnoreFilters: [], + + /** + * Set to true to scan files within symlinks in the build (such as within `pages/`). + */ + followSymlinks: false + } +}) diff --git a/packages/schema/src/config/cli.ts b/packages/schema/src/nuxt2/config/cli.ts similarity index 54% rename from packages/schema/src/config/cli.ts rename to packages/schema/src/nuxt2/config/cli.ts index 93bb4219802..03bc69f8d46 100644 --- a/packages/schema/src/config/cli.ts +++ b/packages/schema/src/nuxt2/config/cli.ts @@ -1,16 +1,16 @@ import { defineUntypedSchema } from 'untyped' export default defineUntypedSchema({ - /** + cli: { + /** * Add a message to the CLI banner by adding a string to this array. * @type {string[]} - * @version 2 */ - badgeMessages: [], + badgeMessages: [], - /** - * Change the color of the 'Nuxt.js' title in the CLI banner. - * @version 2 - */ - bannerColor: 'green' + /** + * Change the color of the 'Nuxt.js' title in the CLI banner. + */ + bannerColor: 'green' + } }) diff --git a/packages/schema/src/nuxt2/config/common.ts b/packages/schema/src/nuxt2/config/common.ts new file mode 100644 index 00000000000..f114899d1ae --- /dev/null +++ b/packages/schema/src/nuxt2/config/common.ts @@ -0,0 +1,260 @@ +import { defineUntypedSchema } from 'untyped' +import createRequire from 'create-require' +import { resolve } from 'pathe' +import { pascalCase } from 'scule' +import jiti from 'jiti' + +export default defineUntypedSchema({ + /** + * Your preferred code editor to launch when debugging. + * + * @see [documentation](https://github.com/yyx990803/launch-editor#supported-editors) + * @type {string} + */ + editor: undefined, + + /** + * The watch property lets you watch custom files for restarting the server. + * + * `chokidar` is used to set up the watchers. To learn more about its pattern + * options, see chokidar documentation. + * + * @see [chokidar](https://github.com/paulmillr/chokidar#api) + * + * @example + * ```js + * watch: ['~/custom/*.js'] + * ``` + * @type {string[]} + */ + watch: { + $resolve: async (val, get) => { + const rootDir = await get('rootDir') + return Array.from(new Set([].concat(val, await get('_nuxtConfigFiles')) + .filter(Boolean).map(p => resolve(rootDir, p)) + )) + } + }, + + /** + * The style extensions that should be resolved by the Nuxt resolver (for example, in `css` property). + */ + styleExtensions: ['.css', '.pcss', '.postcss', '.styl', '.stylus', '.scss', '.sass', '.less'], + + dir: { + /** + * The assets directory (aliased as `~assets` in your build). + */ + assets: 'assets', + + /** + * The directory containing app template files like `app.html` and `router.scrollBehavior.js` + */ + app: 'app', + + /** + * Allows customizing the global ID used in the main HTML template as well as the main + * Vue instance name and other options. + */ + globalName: { + $resolve: val => (typeof val === 'string' && /^[a-zA-Z]+$/.test(val)) ? val.toLocaleLowerCase() : 'nuxt' + }, + + /** + * Whether to produce a separate modern build targeting browsers that support ES modules. + * + * Set to `'server'` to enable server mode, where the Nuxt server checks + * browser version based on the user agent and serves the correct bundle. + * + * Set to `'client'` to serve both the modern bundle with `