refactor: enable strict type checking everywhere (#6943)

This commit is contained in:
Anthony Fu 2022-08-26 23:47:29 +08:00 committed by GitHub
parent 56c7b6168c
commit 9db2229f70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 365 additions and 273 deletions

View File

@ -20,7 +20,7 @@
"pathe": "^0.3.5",
"rimraf": "^3.0.2",
"scule": "^0.3.2",
"untyped": "^0.4.5",
"untyped": "^0.4.7",
"vue-mq": "^1.0.1",
"vue-plausible": "^1.3.2"
},

View File

@ -30,7 +30,7 @@
"semver": "^7.3.7",
"unctx": "^2.0.1",
"unimport": "^0.6.7",
"untyped": "^0.4.5"
"untyped": "^0.4.7"
},
"devDependencies": {
"@types/lodash.template": "^4",

View File

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"strict": true,
"noImplicitAny": true
},
"include": [
"./src/**/*.ts",
"./test/**/*.ts"
]
}

View File

@ -21,6 +21,7 @@
"@nuxt/kit": "3.0.0-rc.8",
"@nuxt/schema": "3.0.0-rc.8",
"@types/clear": "^0",
"@types/flat": "^5.0.2",
"@types/mri": "^1.1.1",
"@types/semver": "^7",
"c12": "^0.2.9",

View File

@ -1,4 +1,5 @@
import type { AddressInfo } from 'node:net'
import { RequestListener } from 'node:http'
import { resolve, relative, normalize } from 'pathe'
import chokidar from 'chokidar'
import { debounce } from 'perfect-debounce'
@ -24,15 +25,15 @@ export default defineNuxtCommand({
overrideEnv('development')
const { listen } = await import('listhen')
let currentHandler
let currentHandler: RequestListener | undefined
let loadingMessage = 'Nuxt is starting...'
const loadingHandler = async (_req, res) => {
const loadingHandler: RequestListener = async (_req, res) => {
const { loading: loadingTemplate } = await importModule('@nuxt/ui-templates')
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
res.statusCode = 503 // Service Unavailable
res.end(loadingTemplate({ loading: loadingMessage }))
}
const serverHandler = (req, res) => {
const serverHandler: RequestListener = (req, res) => {
return currentHandler ? currentHandler(req, res) : loadingHandler(req, res)
}
@ -64,7 +65,7 @@ export default defineNuxtCommand({
const load = async (isRestart: boolean, reason?: string) => {
try {
loadingMessage = `${reason ? reason + '. ' : ''}${isRestart ? 'Restarting' : 'Starting'} nuxt...`
currentHandler = null
currentHandler = undefined
if (isRestart) {
consola.info(loadingMessage)
}
@ -103,7 +104,7 @@ export default defineNuxtCommand({
}
} catch (err) {
consola.error(`Cannot ${isRestart ? 'restart' : 'start'} nuxt: `, err)
currentHandler = null
currentHandler = undefined
loadingMessage = 'Error while loading nuxt. Please check console and fix errors.'
}
}

View File

@ -1,6 +1,6 @@
import type { Argv } from 'mri'
const _rDefault = r => r.default || r
const _rDefault = (r: any) => r.default || r
export const commands = {
dev: () => import('./dev').then(_rDefault),

View File

@ -6,6 +6,7 @@ import jiti from 'jiti'
import destr from 'destr'
import { splitByCase } from 'scule'
import clipboardy from 'clipboardy'
import { NuxtModule } from '@nuxt/schema'
import { getPackageManager, getPackageManagerVersion } from '../utils/packageManagers'
import { findup } from '../utils/fs'
import { defineNuxtCommand } from './index'
@ -27,13 +28,13 @@ export default defineNuxtCommand({
const { dependencies = {}, devDependencies = {} } = findPackage(rootDir)
// Utils to query a dependency version
const getDepVersion = name => getPkg(name, rootDir)?.version || dependencies[name] || devDependencies[name]
const getDepVersion = (name: string) => getPkg(name, rootDir)?.version || dependencies[name] || devDependencies[name]
const listModules = (arr = []) => arr
.map(normalizeConfigModule)
.map(m => normalizeConfigModule(m, rootDir))
.filter(Boolean)
.map((name) => {
const npmName = name.split('/').splice(0, 2).join('/') // @foo/bar/baz => @foo/bar
const npmName = name!.split('/').splice(0, 2).join('/') // @foo/bar/baz => @foo/bar
const v = getDepVersion(npmName)
return '`' + (v ? `${name}@${v}` : name) + '`'
})
@ -54,6 +55,7 @@ export default defineNuxtCommand({
if (packageManager) {
packageManager += '@' + getPackageManagerVersion(packageManager)
} else {
// @ts-expect-error
packageManager = 'unknown'
}
@ -95,14 +97,14 @@ export default defineNuxtCommand({
}
})
function normalizeConfigModule (module, rootDir) {
function normalizeConfigModule (module: NuxtModule | string | null | undefined, rootDir: string): string | null {
if (!module) {
return null
}
if (typeof module === 'string') {
return module
.split(rootDir).pop() // Strip rootDir
.split('node_modules').pop() // Strip node_modules
.split(rootDir).pop()! // Strip rootDir
.split('node_modules').pop()! // Strip node_modules
.replace(/^\//, '')
}
if (typeof module === 'function') {
@ -111,9 +113,10 @@ function normalizeConfigModule (module, rootDir) {
if (Array.isArray(module)) {
return normalizeConfigModule(module[0], rootDir)
}
return null
}
function getNuxtConfig (rootDir) {
function getNuxtConfig (rootDir: string) {
try {
return jiti(rootDir, { interopDefault: true, esmResolve: true })('./nuxt.config')
} catch (err) {
@ -122,7 +125,7 @@ function getNuxtConfig (rootDir) {
}
}
function getPkg (name, rootDir) {
function getPkg (name: string, rootDir: string) {
// Assume it is in {rootDir}/node_modules/${name}/package.json
let pkgPath = resolve(rootDir, 'node_modules', name, 'package.json')
@ -135,7 +138,7 @@ function getPkg (name, rootDir) {
return readJSONSync(pkgPath)
}
function findPackage (rootDir) {
function findPackage (rootDir: string) {
return findup(rootDir, (dir) => {
const p = resolve(dir, 'package.json')
if (existsSync(p)) {
@ -144,7 +147,7 @@ function findPackage (rootDir) {
}) || {}
}
function readJSONSync (filePath) {
function readJSONSync (filePath: string) {
try {
return destr(readFileSync(filePath, 'utf-8'))
} catch (err) {

View File

@ -1,13 +1,14 @@
import { existsSync, readdirSync } from 'node:fs'
// @ts-expect-error missing types
import createTiged from 'tiged'
import { relative, resolve } from 'pathe'
import superb from 'superb'
import consola from 'consola'
import { defineNuxtCommand } from './index'
const rpath = p => relative(process.cwd(), p)
const rpath = (p: string) => relative(process.cwd(), p)
const resolveTemplate = (template) => {
const resolveTemplate = (template: string | boolean) => {
if (typeof template === 'boolean') {
consola.error('Please specify a template!')
process.exit(1)
@ -39,12 +40,12 @@ export default defineNuxtCommand({
consola.error(`Directory ${dstDir} is not empty. Please pick another name or remove it first. Aborting.`)
process.exit(1)
}
const formatArgs = msg => msg.replace('options.', '--')
tiged.on('warn', event => consola.warn(formatArgs(event.message)))
tiged.on('info', event => consola.info(formatArgs(event.message)))
const formatArgs = (msg: string) => msg.replace('options.', '--')
tiged.on('warn', (event: any) => consola.warn(formatArgs(event.message)))
tiged.on('info', (event: any) => consola.info(formatArgs(event.message)))
try {
await tiged.clone(dstDir)
} catch (e) {
} catch (e: any) {
if (e.toString().includes('could not find commit hash')) {
consola.error(`Failed to clone template from \`${src}\`. Please check the repo is valid and that you have installed \`git\` correctly.`)
process.exit(1)

View File

@ -3,14 +3,14 @@ import { pathToFileURL } from 'node:url'
import { normalize, dirname } from 'pathe'
export function getModulePaths (paths?: string | string[]): string[] {
return [].concat(
return [
// @ts-ignore
global.__NUXT_PREPATHS__,
...(Array.isArray(paths) ? paths : [paths]),
...(paths ? [] : Array.isArray(paths) ? paths : [paths]),
process.cwd(),
// @ts-ignore
global.__NUXT_PATHS__
).filter(Boolean)
].filter(Boolean)
}
const _require = createRequire(process.cwd())

View File

@ -2,19 +2,19 @@ import flatten from 'flat'
import { detailedDiff } from 'deep-object-diff'
import { green, red, blue, cyan } from 'colorette'
function normalizeDiff (diffObj, type, ignore) {
return Object.entries(flatten(diffObj))
function normalizeDiff (diffObj: any, type: 'added' | 'deleted' | 'updated', ignore: string[]) {
return Object.entries(flatten(diffObj) as Record<string, any>)
.map(([key, value]) => ({ key, value, type }))
.filter(item => !ignore.includes(item.key) && typeof item.value !== 'function')
}
export function diff (a, b, ignore) {
export function diff (a: any, b: any, ignore: string[]) {
const _diff: any = detailedDiff(a, b)
return [].concat(
normalizeDiff(_diff.added, 'added', ignore),
normalizeDiff(_diff.deleted, 'deleted', ignore),
normalizeDiff(_diff.updated, 'updated', ignore)
)
return [
...normalizeDiff(_diff.added, 'added', ignore),
...normalizeDiff(_diff.deleted, 'deleted', ignore),
...normalizeDiff(_diff.updated, 'updated', ignore)
]
}
const typeMap = {
@ -23,9 +23,9 @@ const typeMap = {
updated: blue('updated')
}
export function printDiff (diff) {
export function printDiff (diff: any) {
for (const item of diff) {
console.log(' ', typeMap[item.type] || item.type, cyan(item.key), item.value ? `~> ${cyan(item.value)}` : '')
console.log(' ', typeMap[item.type as keyof typeof typeMap] || item.type, cyan(item.key), item.value ? `~> ${cyan(item.value)}` : '')
}
console.log()
}

View File

@ -1,7 +1,10 @@
import { cyan, magenta } from 'colorette'
export function showHelp (meta?) {
import { NuxtCommandMeta } from '../commands'
export function showHelp (meta?: Partial<NuxtCommandMeta>) {
const sections: string[] = []
if (meta) {
if (meta.usage) {
sections.push(magenta('> ') + 'Usage: ' + cyan(meta.usage))
}
@ -9,6 +12,7 @@ export function showHelp (meta?) {
if (meta.description) {
sections.push(magenta('⋮ ') + meta.description)
}
}
sections.push(`Use ${cyan('npx nuxi [command] --help')} to see help for each command`)

View File

@ -3,7 +3,7 @@ import { importModule } from './cjs'
export const loadKit = async (rootDir: string): Promise<typeof import('@nuxt/kit')> => {
try {
return await importModule('@nuxt/kit', rootDir) as typeof import('@nuxt/kit')
} catch (e) {
} catch (e: any) {
if (e.toString().includes("Cannot find module '@nuxt/kit'")) {
throw new Error('nuxi requires `@nuxt/kit` to be installed in your project. Try installing `nuxt3` or `@nuxt/bridge` first.')
}

View File

@ -6,7 +6,7 @@ import type { Nuxt } from '@nuxt/schema'
import { rmRecursive } from './fs'
export interface NuxtProjectManifest {
_hash: string
_hash: string | null
project: {
rootDir: string
},

View File

@ -9,14 +9,17 @@ export const packageManagerLocks = {
pnpm: 'pnpm-lock.yaml'
}
type PackageManager = keyof typeof packageManagerLocks
export function getPackageManager (rootDir: string) {
return findup(rootDir, (dir) => {
for (const name in packageManagerLocks) {
if (existsSync(resolve(dir, packageManagerLocks[name]))) {
const path = packageManagerLocks[name as PackageManager]
if (path && existsSync(resolve(dir, path))) {
return name
}
}
})
}) as PackageManager | null
}
export function getPackageManagerVersion (name: string) {

View File

@ -31,7 +31,7 @@ export const writeTypes = async (nuxt: Nuxt) => {
]
})
const aliases = {
const aliases: Record<string, string> = {
...nuxt.options.alias,
'#build': nuxt.options.buildDir
}
@ -48,6 +48,7 @@ export const writeTypes = async (nuxt: Nuxt) => {
: aliases[alias]
const stats = await fsp.stat(resolve(nuxt.options.rootDir, relativePath)).catch(() => null /* file does not exist */)
tsConfig.compilerOptions = tsConfig.compilerOptions || {}
if (stats?.isDirectory()) {
tsConfig.compilerOptions.paths[alias] = [relativePath]
tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`]

View File

@ -65,7 +65,7 @@
"unenv": "^0.6.1",
"unimport": "^0.6.7",
"unplugin": "^0.9.2",
"untyped": "^0.4.5",
"untyped": "^0.4.7",
"vue": "^3.2.37",
"vue-bundle-renderer": "^0.4.2",
"vue-devtools-stub": "^0.1.0",

View File

@ -144,7 +144,7 @@ export function useAsyncData<
result = options.transform(result)
}
if (options.pick) {
result = pick(result, options.pick) as DataT
result = pick(result as any, options.pick) as DataT
}
asyncData.data.value = result
asyncData.error.value = null

View File

@ -231,7 +231,7 @@ export function normalizePlugins (_plugins: Plugin[]) {
return plugins as Plugin[]
}
export function defineNuxtPlugin<T> (plugin: Plugin<T>) {
export function defineNuxtPlugin<T extends Record<string, any>> (plugin: Plugin<T>) {
plugin[NuxtPluginIndicator] = true
return plugin
}

View File

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"strict": true,
"noImplicitAny": true
},
"include": [
"./src/**/*.ts",
"./test/**/*.ts"
]
}

View File

@ -41,6 +41,7 @@ export default defineBuildConfig({
'ignore',
// Implicit
'@vue/compiler-core',
'@vue/shared'
'@vue/shared',
'untyped'
]
})

View File

@ -17,6 +17,7 @@
"@types/lodash.template": "^4",
"@types/semver": "^7",
"unbuild": "latest",
"untyped": "^0.4.7",
"vite": "~3.0.9"
},
"dependencies": {

View File

@ -1,4 +1,6 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Configure Nuxt component auto-registration.
*
@ -57,4 +59,4 @@ export default {
* @version 3
*/
telemetry: undefined
}
})

View File

@ -1,8 +1,11 @@
import { resolve, join } from 'pathe'
import { existsSync, readdirSync } from 'node:fs'
import defu from 'defu'
import { defineUntypedSchema } from 'untyped'
export default {
import { MetaObject } from '../types/meta'
export default defineUntypedSchema({
/**
* Vue.js config
* @version 2
@ -17,8 +20,12 @@ export default {
* @version 2
*/
config: {
silent: { $resolve: (val, get) => val ?? !get('dev') },
performance: { $resolve: (val, get) => val ?? get('dev') },
silent: {
$resolve: (val, get) => val ?? !get('dev')
},
performance: {
$resolve: (val, get) => val ?? get('dev')
},
},
/**
* Options for the Vue compiler that will be passed at build time.
@ -105,7 +112,7 @@ export default {
*/
head: {
$resolve: (val, get) => {
const resolved = defu(val, get('meta'), {
const resolved: Required<MetaObject> = defu(val, get('meta'), {
meta: [],
link: [],
style: [],
@ -306,7 +313,7 @@ export default {
* @version 3
*/
css: {
$resolve: val => (val ?? []).map(c => c.src || c)
$resolve: val => (val ?? []).map((c: any) => c.src || c)
},
/**
@ -460,4 +467,4 @@ export default {
/** Set to false to disable the `<ClientOnly>` component (see [docs](https://github.com/egoist/vue-client-only)) */
componentClientOnly: true
}
}
})

View File

@ -4,9 +4,12 @@ import createRequire from 'create-require'
import { pascalCase } from 'scule'
import jiti from 'jiti'
import defu from 'defu'
import { RuntimeConfig } from '../types/config'
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Extend nested configurations from multiple local or remote sources.
*
@ -152,12 +155,13 @@ export default {
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 => jiti(typeof p === 'string' ? p : p.filename, { esmResolve: true })
return (p: string | { filename: string }) => jiti(typeof p === 'string' ? p : p.filename, { esmResolve: true })
}
if (val === 'native') {
return p => createRequire(typeof p === 'string' ? p : p.filename)
return (p: string | { filename: string }) => createRequire(typeof p === 'string' ? p : p.filename)
}
return val
}
@ -312,17 +316,17 @@ export default {
*/
globals: {
/** @type {(globalName: string) => string} */
id: globalName => `__${globalName}`,
id: (globalName: string) => `__${globalName}`,
/** @type {(globalName: string) => string} */
nuxt: globalName => `$${globalName}`,
nuxt: (globalName: string) => `$${globalName}`,
/** @type {(globalName: string) => string} */
context: globalName => `__${globalName.toUpperCase()}__`,
context: (globalName: string) => `__${globalName.toUpperCase()}__`,
/** @type {(globalName: string) => string} */
pluginPrefix: globalName => globalName,
pluginPrefix: (globalName: string) => globalName,
/** @type {(globalName: string) => string} */
readyCallback: globalName => `on${pascalCase(globalName)}Ready`,
readyCallback: (globalName: string) => `on${pascalCase(globalName)}Ready`,
/** @type {(globalName: string) => string} */
loadedCallback: globalName => `_on${pascalCase(globalName)}Loaded`
loadedCallback: (globalName: string) => `_on${pascalCase(globalName)}Loaded`
},
/**
@ -427,10 +431,10 @@ export default {
*/
modulesDir: {
$default: ['node_modules'],
$resolve: (val, get) => [].concat(
val.map(dir => resolve(get('rootDir'), dir)),
$resolve: (val, get) => [
...val.map((dir: string) => resolve(get('rootDir'), dir)),
resolve(process.cwd(), 'node_modules')
)
]
},
/**
@ -759,4 +763,4 @@ export default {
* @version 3
*/
appConfig: {},
}
})

View File

@ -1,4 +1,6 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/** @private */
_majorVersion: 2,
/** @private */
@ -21,4 +23,4 @@ export default {
_nuxtConfigFiles: [],
/** @private */
appDir: ''
}
})

View File

@ -2,8 +2,9 @@ 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 {
export default defineUntypedSchema({
/**
* The builder to use for bundling the Vue part of your application.
*
@ -15,7 +16,7 @@ export default {
if (typeof val === 'object') {
return val
}
const map = {
const map: Record<string, string> = {
vite: '@nuxt/vite-builder',
webpack: '@nuxt/webpack-builder',
}
@ -225,15 +226,16 @@ export default {
* chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js')
* }
* ```
* @type {Record<string, ((arg: any) => string)>}
* @version 2
*/
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]'
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]'
},
/**
@ -360,7 +362,9 @@ export default {
optimization: {
runtimeChunk: 'single',
/** Set minimize to false to disable all minimizers. (It is disabled in development by default) */
minimize: { $resolve: (val, get) => val ?? !get('dev') },
minimize: {
$resolve: (val, get) => val ?? !get('dev')
},
/** You can set minimizer to a customized array of plugins. */
minimizer: undefined,
splitChunks: {
@ -639,4 +643,4 @@ export default {
*/
followSymlinks: false
}
}
})

View File

@ -1,4 +1,6 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Add a message to the CLI banner by adding a string to this array.
* @type {string[]}
@ -11,4 +13,4 @@ export default {
* @version 2
*/
bannerColor: 'green'
}
})

View File

@ -1,11 +1,13 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/** @version 3 */
experimental: {
/**
* Set to true to generate an async entry point for the Vue bundle (for module federation support).
*/
asyncEntry: {
$resolve: (val, get) => val ?? false
$resolve: (val) => val ?? false
},
/**
@ -51,4 +53,4 @@ export default {
*/
viteServerDynamicImports: true
}
}
})

View File

@ -1,10 +1,11 @@
import { resolve } from 'pathe'
import { joinURL } from 'ufo'
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default {
export default <SchemaDefinition> {
/**
* Directory name that holds all the assets and generated pages for a `static` build.
*/
@ -160,10 +161,16 @@ export default {
* The full path to the directory underneath `/_nuxt/` where static assets
* (payload, state and manifest files) will live.
*/
base: { $resolve: (val, get) => val || joinURL(get('app').buildAssetsDir, get('generate.dir')) },
/** The full path to the versioned directory where static assets for the current buidl are located. */
versionBase: { $resolve: (val, get) => val || joinURL(get('generate.base'), get('generate.version')) },
base: {
$resolve: (val, get) => val || joinURL(get('app').buildAssetsDir, get('generate.dir'))
},
/** The full path to the versioned directory where static assets for the current build are located. */
versionBase: {
$resolve: (val, get) => val || joinURL(get('generate.base'), get('generate.version'))
},
/** A unique string to uniquely identify payload versions (defaults to the current timestamp). */
version: { $resolve: val => val || (String(Math.round(Date.now() / 1000))) }
version: {
$resolve: val => val || (String(Math.round(Date.now() / 1000)))
}
}
}

View File

@ -1,7 +1,9 @@
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default {
export default <SchemaDefinition> {
/** The text that displays on the Nuxt loading indicator when `ssr: false`. */
loading: 'Loading...',
/** The 404 text on the default Nuxt error page. */

View File

@ -1,4 +1,6 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Configuration for Nitro.
*
@ -31,4 +33,4 @@ export default {
* @version 3
*/
devServerHandlers: []
}
})

View File

@ -1,7 +1,8 @@
import defu from 'defu'
import createResolver from 'postcss-import-resolver'
import { defineUntypedSchema } from 'untyped'
export default {
export default defineUntypedSchema({
/** @version 3 */
postcss: {
/** Path to postcss config file. */
@ -51,4 +52,4 @@ export default {
}
}
}
}
})

View File

@ -1,7 +1,9 @@
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default {
export default <SchemaDefinition>{
/**
* Use this option to customize the Vue SSR bundle renderer.
* This option is skipped if `ssr: false`.
@ -10,9 +12,11 @@ export default {
*/
bundleRenderer: {
shouldPrefetch: () => false,
shouldPreload: (_fileWithoutQuery, asType) => ['script', 'style'].includes(asType),
shouldPreload: (_fileWithoutQuery: string, asType: string) => ['script', 'style'].includes(asType),
/** enabled by default for development */
runInNewContext: { $resolve: (val, get) => val ?? get('dev') }
runInNewContext: {
$resolve: (val, get) => val ?? get('dev')
}
},
/**
@ -41,7 +45,9 @@ export default {
*
* Set to `collapsed` to collapse the logs, or `false` to disable.
*/
ssrLog: { $resolve: (val, get) => get('dev') ? Boolean(val) : false },
ssrLog: {
$resolve: (val, get) => get('dev') ? Boolean(val) : false
},
/**
* Configuration for HTTP2 push headers.

View File

@ -1,6 +1,7 @@
import { normalizeURL, withTrailingSlash } from 'ufo'
import { defineUntypedSchema } from 'untyped'
export default {
export default defineUntypedSchema({
/**
* Additional options passed to `vue-router`.
*
@ -168,4 +169,4 @@ export default {
* @version 2
*/
trailingSlash: undefined
}
})

View File

@ -1,5 +1,7 @@
import { SchemaDefinition } from 'untyped'
/** @version 2 */
export default {
export default <SchemaDefinition>{
/**
* Whether to enable HTTPS.
*

View File

@ -1,4 +1,6 @@
export default {
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Configuration for Nuxt's TypeScript integration.
*
@ -35,4 +37,4 @@ export default {
*/
shim: true
}
}
})

View File

@ -1,7 +1,8 @@
import { resolve } from 'pathe'
import { withoutLeadingSlash } from 'ufo'
import { defineUntypedSchema } from 'untyped'
export default {
export default defineUntypedSchema({
/**
* Configuration that will be passed directly to Vite.
*
@ -45,7 +46,7 @@ export default {
exclude: {
$resolve: (val, get) => [
...val || [],
...get('build.transpile').filter((i) => typeof i === 'string'),
...get('build.transpile').filter((i: string) => typeof i === 'string'),
'vue-demi'
]
}
@ -77,4 +78,4 @@ export default {
}
}
}
}
})

View File

@ -1,6 +1,7 @@
import { join } from 'pathe'
import { defineUntypedSchema } from 'untyped'
export default {
export default defineUntypedSchema({
/** @version 3 */
webpack: {
/**
@ -122,12 +123,12 @@ export default {
* ```
*/
filenames: {
app: ({ isDev }) => isDev ? `[name].js` : `[contenthash:7].js`,
chunk: ({ isDev }) => isDev ? `[name].js` : `[contenthash:7].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]'
app: ({ isDev }: { isDev: boolean }) => isDev ? `[name].js` : `[contenthash:7].js`,
chunk: ({ isDev }: { isDev: boolean }) => isDev ? `[name].js` : `[contenthash:7].js`,
css: ({ isDev }: { isDev: boolean }) => isDev ? '[name].css' : 'css/[contenthash:7].css',
img: ({ isDev }: { isDev: boolean }) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
font: ({ isDev }: { isDev: boolean }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
video: ({ isDev }: { isDev: boolean }) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
},
/**
@ -297,4 +298,4 @@ export default {
*/
warningIgnoreFilters: [],
}
}
})

View File

@ -71,10 +71,10 @@ export interface ModuleContainer {
addServerMiddleware(arg1: any): void
/** Allows extending webpack build config by chaining `options.build.extend` function. */
extendBuild(fn): void
extendBuild(fn: Function): void
/** Allows extending routes by chaining `options.router.extendRoutes` function. */
extendRoutes(fn): void
extendRoutes(fn: Function): void
/** Registers a module. */
requireModule(installOptions: any, opts: any): Promise<void>

View File

@ -31,7 +31,7 @@ export async function getBrowser (): Promise<Browser> {
if (!ctx.browser) {
await createBrowser()
}
return ctx.browser
return ctx.browser!
}
export async function createPage (path?: string, options?: BrowserContextOptions) {

View File

@ -2,7 +2,7 @@ import { resolve } from 'node:path'
import defu from 'defu'
import type { TestContext, TestOptions, TestRunner } from './types'
let currentContext: TestContext
let currentContext: TestContext | undefined
export function createTestContext (options: Partial<TestOptions>): TestContext {
const _options: Partial<TestOptions> = defu(options, {
@ -18,7 +18,7 @@ export function createTestContext (options: Partial<TestOptions>): TestContext {
// TODO: auto detect based on process.env
runner: <TestRunner>'vitest',
browserOptions: {
type: 'chromium'
type: 'chromium' as const
}
})
@ -32,7 +32,9 @@ export function useTestContext (): TestContext {
return currentContext
}
export function setTestContext (context: TestContext): TestContext {
export function setTestContext (context: TestContext): TestContext
export function setTestContext (context?: TestContext): TestContext | undefined
export function setTestContext (context?: TestContext): TestContext | undefined {
currentContext = context
return currentContext
}

View File

@ -64,5 +64,5 @@ export async function loadFixture () {
export async function buildFixture () {
const ctx = useTestContext()
await kit.buildNuxt(ctx.nuxt)
await kit.buildNuxt(ctx.nuxt!)
}

View File

@ -21,6 +21,7 @@ export async function runTests (opts: RunTestOptions) {
process.env.NUXT_TEST_DEV = 'true'
}
// @ts-ignore missing types
const { startVitest } = await import('vitest/dist/node.mjs')
const succeeded = await startVitest(
[] /* argv */,

View File

@ -16,7 +16,7 @@ export async function startServer () {
if (ctx.options.dev) {
const nuxiCLI = await kit.resolvePath('nuxi/cli')
ctx.serverProcess = execa(nuxiCLI, ['dev'], {
cwd: ctx.nuxt.options.rootDir,
cwd: ctx.nuxt!.options.rootDir,
stdio: 'inherit',
env: {
...process.env,
@ -37,7 +37,7 @@ export async function startServer () {
throw new Error('Timeout waiting for dev server!')
} else {
ctx.serverProcess = execa('node', [
resolve(ctx.nuxt.options.nitro.output.dir, 'server/index.mjs')
resolve(ctx.nuxt!.options.nitro.output!.dir!, 'server/index.mjs')
], {
stdio: 'inherit',
env: {

View File

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"strict": true,
"noImplicitAny": true
},
"include": [
"./src/**/*.ts",
"./test/**/*.ts"
]
}

View File

@ -58,6 +58,7 @@
},
"devDependencies": {
"@nuxt/schema": "3.0.0-rc.8",
"@types/lodash-es": "^4.17.6",
"@types/pify": "^5.0.1",
"@types/webpack-bundle-analyzer": "^4.4.2",
"@types/webpack-dev-middleware": "^5.0.2",

View File

@ -68,6 +68,7 @@ function clientHMR (ctx: WebpackConfigContext) {
`webpack-hot-middleware/client?${hotMiddlewareClientOptionsStr}`
)
config.plugins = config.plugins || []
config.plugins.push(new webpack.HotModuleReplacementPlugin())
}

View File

@ -26,7 +26,7 @@ export function server (ctx: WebpackConfigContext) {
function serverPreset (ctx: WebpackConfigContext) {
const { config } = ctx
config.output.filename = 'server.mjs'
config.output!.filename = 'server.mjs'
config.devtool = 'cheap-module-source-map'
config.optimization = {
@ -53,8 +53,11 @@ function serverStandalone (ctx: WebpackConfigContext) {
if (!Array.isArray(ctx.config.externals)) { return }
ctx.config.externals.push(({ request }, cb) => {
if (!request) {
return cb(undefined, false)
}
if (external.includes(request)) {
return cb(null, true)
return cb(undefined, true)
}
if (
request[0] === '.' ||
@ -63,16 +66,18 @@ function serverStandalone (ctx: WebpackConfigContext) {
assetPattern.test(request)
) {
// console.log('Inline', request)
return cb(null, false)
return cb(undefined, false)
}
// console.log('Ext', request)
return cb(null, true)
return cb(undefined, true)
})
}
function serverPlugins (ctx: WebpackConfigContext) {
const { config, options } = ctx
config.plugins = config.plugins || []
// Server polyfills
if (options.webpack.serverURLPolyfill) {
config.plugins.push(new webpack.ProvidePlugin({
@ -83,6 +88,6 @@ function serverPlugins (ctx: WebpackConfigContext) {
// Add type-checking
if (ctx.nuxt.options.typescript.typeCheck === true || (ctx.nuxt.options.typescript.typeCheck === 'build' && !ctx.nuxt.options.dev)) {
ctx.config.plugins.push(new ForkTSCheckerWebpackPlugin({ logger }))
config.plugins.push(new ForkTSCheckerWebpackPlugin({ logger }))
}
}

View File

@ -24,7 +24,9 @@ export const DynamicBasePlugin = createUnplugin((options: DynamicBasePluginOptio
s.append(`${options.globalPublicPath} = buildAssetsURL();\n`)
return {
code: s.toString(),
map: options.sourcemap && s.generateMap({ source: id, includeContent: true })
map: options.sourcemap
? s.generateMap({ source: id, includeContent: true })
: undefined
}
}
}

View File

@ -10,6 +10,7 @@ import { uniq } from 'lodash-es'
import fse from 'fs-extra'
import type { Nuxt } from '@nuxt/schema'
import type { Compilation, Compiler } from 'webpack'
import { isJS, isCSS, isHotUpdate } from './util'
interface PluginOptions {
@ -26,17 +27,17 @@ export default class VueSSRClientPlugin {
}, options)
}
apply (compiler) {
compiler.hooks.afterEmit.tap('VueSSRClientPlugin', async (compilation: any) => {
apply (compiler: Compiler) {
compiler.hooks.afterEmit.tap('VueSSRClientPlugin', async (compilation: Compilation) => {
const stats = compilation.getStats().toJson()
const allFiles = uniq(stats.assets
const allFiles = uniq(stats.assets!
.map(a => a.name))
.filter(file => !isHotUpdate(file))
const initialFiles = uniq(Object.keys(stats.entrypoints)
.map(name => stats.entrypoints[name].assets)
.reduce((files, entryAssets) => files.concat(entryAssets.map(entryAsset => entryAsset.name)), [])
const initialFiles = uniq(Object.keys(stats.entrypoints!)
.map(name => stats.entrypoints![name].assets!)
.reduce((files, entryAssets) => files.concat(entryAssets.map(entryAsset => entryAsset.name)), [] as string[])
.filter(file => isJS(file) || isCSS(file)))
.filter(file => !isHotUpdate(file))
@ -45,11 +46,11 @@ export default class VueSSRClientPlugin {
.filter(file => !initialFiles.includes(file))
.filter(file => !isHotUpdate(file))
const assetsMapping = {}
stats.assets
const assetsMapping: Record<string, string[]> = {}
stats.assets!
.filter(({ name }) => isJS(name))
.filter(({ name }) => !isHotUpdate(name))
.forEach(({ name, chunkNames }) => {
.forEach(({ name, chunkNames = [] }) => {
const componentHash = hash(chunkNames.join('|'))
if (!assetsMapping[componentHash]) {
assetsMapping[componentHash] = []
@ -62,29 +63,29 @@ export default class VueSSRClientPlugin {
all: allFiles,
initial: initialFiles,
async: asyncFiles,
modules: { /* [identifier: string]: Array<index: number> */ },
modules: { /* [identifier: string]: Array<index: number> */ } as Record<string, number[]>,
assetsMapping
}
const { entrypoints, namedChunkGroups } = stats
const assetModules = stats.modules.filter(m => m.assets.length)
const fileToIndex = file => webpackManifest.all.indexOf(file)
stats.modules.forEach((m) => {
const { entrypoints = {}, namedChunkGroups = {} } = stats
const assetModules = stats.modules!.filter(m => m.assets!.length)
const fileToIndex = (file: string) => webpackManifest.all.indexOf(file)
stats.modules!.forEach((m) => {
// Ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
const [cid] = m.chunks
const chunk = stats.chunks.find(c => c.id === cid)
if (m.chunks!.length === 1) {
const [cid] = m.chunks!
const chunk = stats.chunks!.find(c => c.id === cid)
if (!chunk || !chunk.files) {
return
}
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
const id = m.identifier!.replace(/\s\w+$/, '') // remove appended hash
const filesSet = new Set(chunk.files.map(fileToIndex).filter(i => i !== -1))
for (const chunkName of chunk.names) {
for (const chunkName of chunk.names!) {
if (!entrypoints[chunkName]) {
const chunkGroup = namedChunkGroups[chunkName]
if (chunkGroup) {
for (const asset of chunkGroup.assets) {
for (const asset of chunkGroup.assets!) {
filesSet.add(fileToIndex(asset.name))
}
}
@ -98,7 +99,7 @@ export default class VueSSRClientPlugin {
// Include ConcatenatedModule for not losing module-component mapping
if (Array.isArray(m.modules)) {
for (const concatenatedModule of m.modules) {
const id = hash(concatenatedModule.identifier.replace(/\s\w+$/, ''))
const id = hash(concatenatedModule.identifier!.replace(/\s\w+$/, ''))
if (!webpackManifest.modules[id]) {
webpackManifest.modules[id] = files
}
@ -107,14 +108,14 @@ export default class VueSSRClientPlugin {
// Find all asset modules associated with the same chunk
assetModules.forEach((m) => {
if (m.chunks.includes(cid)) {
files.push.apply(files, m.assets.map(fileToIndex))
if (m.chunks!.includes(cid)) {
files.push.apply(files, (m.assets as string[]).map(fileToIndex))
}
})
}
})
const manifest = normalizeWebpackManifest(webpackManifest)
const manifest = normalizeWebpackManifest(webpackManifest as any)
await this.options.nuxt.callHook('build:manifest', manifest)
const src = JSON.stringify(manifest, null, 2)

View File

@ -1,35 +1,36 @@
import webpack from 'webpack'
import webpack, { Compilation, Compiler } from 'webpack'
import { validate, isJS, extractQueryPartJS } from './util'
export default class VueSSRServerPlugin {
options: {
filename?: string
}
export interface VueSSRServerPluginOptions {
filename: string
}
constructor (options = {}) {
export default class VueSSRServerPlugin {
options: VueSSRServerPluginOptions
constructor (options: Partial<VueSSRServerPluginOptions> = {}) {
this.options = Object.assign({
filename: null
}, options)
}, options) as VueSSRServerPluginOptions
}
apply (compiler) {
apply (compiler: Compiler) {
validate(compiler)
compiler.hooks.make.tap('VueSSRServerPlugin', (compilation: any) => {
compiler.hooks.make.tap('VueSSRServerPlugin', (compilation: Compilation) => {
compilation.hooks.processAssets.tapAsync({
name: 'VueSSRServerPlugin',
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
}, (assets, cb) => {
}, (assets: any, cb: any) => {
const stats = compilation.getStats().toJson()
const [entryName] = Object.keys(stats.entrypoints)
const entryInfo = stats.entrypoints[entryName]
const [entryName] = Object.keys(stats.entrypoints!)
const entryInfo = stats.entrypoints![entryName]
if (!entryInfo) {
// #5553
return cb()
}
const entryAssets = entryInfo.assets.filter(asset => isJS(asset.name))
const entryAssets = entryInfo.assets!.filter((asset: { name:string }) => isJS(asset.name))
if (entryAssets.length > 1) {
throw new Error(
@ -47,11 +48,11 @@ export default class VueSSRServerPlugin {
const bundle = {
entry: entry.name,
files: {},
maps: {}
files: {} as Record<string, string>,
maps: {} as Record<string, string>
}
stats.assets.forEach((asset) => {
stats.assets!.forEach((asset: any) => {
if (isJS(asset.name)) {
const queryPart = extractQueryPartJS(asset.name)
if (queryPart !== undefined) {

View File

@ -4,8 +4,9 @@
*/
import { logger } from '@nuxt/kit'
import type { Compiler } from 'webpack'
export const validate = (compiler) => {
export const validate = (compiler: Compiler) => {
if (compiler.options.target !== 'node') {
logger.warn('webpack config `target` should be "node".')
}
@ -20,10 +21,10 @@ export const validate = (compiler) => {
const isJSRegExp = /\.[cm]?js(\?[^.]+)?$/
export const isJS = file => isJSRegExp.test(file)
export const isJS = (file: string) => isJSRegExp.test(file)
export const extractQueryPartJS = file => isJSRegExp.exec(file)[1]
export const extractQueryPartJS = (file: string) => isJSRegExp.exec(file)?.[1]
export const isCSS = file => /\.css(\?[^.]+)?$/.test(file)
export const isCSS = (file: string) => /\.css(\?[^.]+)?$/.test(file)
export const isHotUpdate = file => file.includes('hot-update')
export const isHotUpdate = (file: string) => file.includes('hot-update')

View File

@ -1,7 +1,7 @@
import { fileName, WebpackConfigContext } from '../utils/config'
export function assets (ctx: WebpackConfigContext) {
ctx.config.module.rules.push(
ctx.config.module!.rules!.push(
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [{

View File

@ -1,8 +1,10 @@
import { resolve, normalize } from 'pathe'
// @ts-expect-error missing types
import TimeFixPlugin from 'time-fix-plugin'
import WebpackBar from 'webpackbar'
import webpack from 'webpack'
import { logger } from '@nuxt/kit'
// @ts-expect-error missing types
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
import escapeRegExp from 'escape-string-regexp'
import { joinURL } from 'ufo'
@ -44,6 +46,8 @@ function baseConfig (ctx: WebpackConfigContext) {
function basePlugins (ctx: WebpackConfigContext) {
const { config, options, nuxt } = ctx
config.plugins = config.plugins || []
// Add timefix-plugin before other plugins
if (options.dev) {
config.plugins.push(new TimeFixPlugin())
@ -63,7 +67,7 @@ function basePlugins (ctx: WebpackConfigContext) {
ctx.isServer ||
(ctx.isDev && !options.build.quiet && options.webpack.friendlyErrors)
) {
ctx.config.plugins.push(
config.plugins.push(
new FriendlyErrorsWebpackPlugin({
clearConsole: false,
reporter: 'consola',
@ -81,7 +85,7 @@ function basePlugins (ctx: WebpackConfigContext) {
}
config.plugins.push(new WebpackBar({
name: ctx.name,
color: colors[ctx.name],
color: colors[ctx.name as keyof typeof colors],
reporters: ['stats'],
stats: !ctx.isDev,
reporter: {
@ -91,6 +95,7 @@ function basePlugins (ctx: WebpackConfigContext) {
nuxt.callHook('bundler:change', shortPath)
}
},
// @ts-ignore
done: ({ state }) => {
if (state.hasErrors) {
nuxt.callHook('bundler:error')
@ -101,6 +106,7 @@ function basePlugins (ctx: WebpackConfigContext) {
allDone: () => {
nuxt.callHook('bundler:done')
},
// @ts-ignore
progress ({ statesArray }) {
nuxt.callHook('bundler:progress', statesArray)
}
@ -220,7 +226,7 @@ function getWarningIgnoreFilter (ctx: WebpackConfigContext): WarningFilter {
function getEnv (ctx: WebpackConfigContext) {
const { options } = ctx
const _env = {
const _env: Record<string, string | boolean> = {
'process.env.NODE_ENV': JSON.stringify(ctx.config.mode),
'process.mode': JSON.stringify(ctx.config.mode),
'process.dev': options.dev,
@ -239,7 +245,7 @@ function getEnv (ctx: WebpackConfigContext) {
Object.entries(options.env).forEach(([key, value]) => {
const isNative = ['boolean', 'number'].includes(typeof value)
_env['process.env.' + key] = isNative ? value : JSON.stringify(value)
_env['process.env.' + key] = isNative ? value as string : JSON.stringify(value)
})
return _env

View File

@ -10,9 +10,9 @@ export function esbuild (ctx: WebpackConfigContext) {
const target = ctx.isServer ? 'es2019' : 'chrome85'
// https://github.com/nuxt/framework/issues/2372
config.optimization.minimizer.push(new (esbuildLoader as unknown as typeof import('esbuild-loader')).ESBuildMinifyPlugin())
config.optimization!.minimizer!.push(new (esbuildLoader as unknown as typeof import('esbuild-loader')).ESBuildMinifyPlugin())
config.module.rules.push(
config.module!.rules!.push(
{
test: /\.m?[jt]s$/i,
loader: 'esbuild-loader',

View File

@ -6,7 +6,7 @@ export function node (ctx: WebpackConfigContext) {
config.target = 'node'
config.node = false
config.experiments.outputModule = true
config.experiments!.outputModule = true
config.output = {
...config.output,

View File

@ -1,7 +1,7 @@
import { WebpackConfigContext } from '../utils/config'
export function pug (ctx: WebpackConfigContext) {
ctx.config.module.rules.push({
ctx.config.module!.rules!.push({
test: /\.pug$/i,
oneOf: [
{

View File

@ -14,8 +14,8 @@ export function style (ctx: WebpackConfigContext) {
function minimizer (ctx: WebpackConfigContext) {
const { options, config } = ctx
if (options.webpack.optimizeCSS && Array.isArray(config.optimization.minimizer)) {
config.optimization.minimizer.push(new CssMinimizerPlugin({
if (options.webpack.optimizeCSS && Array.isArray(config.optimization!.minimizer)) {
config.optimization!.minimizer.push(new CssMinimizerPlugin({
...options.webpack.optimizeCSS
}))
}
@ -26,7 +26,7 @@ function extractCSS (ctx: WebpackConfigContext) {
// CSS extraction
if (options.webpack.extractCSS) {
config.plugins.push(new MiniCssExtractPlugin({
config.plugins!.push(new MiniCssExtractPlugin({
filename: fileName(ctx, 'css'),
chunkFilename: fileName(ctx, 'css'),
...options.webpack.extractCSS === true ? {} : options.webpack.extractCSS
@ -38,28 +38,28 @@ function loaders (ctx: WebpackConfigContext) {
const { config, options } = ctx
// CSS
config.module.rules.push(createdStyleRule('css', /\.css$/i, null, ctx))
config.module!.rules!.push(createdStyleRule('css', /\.css$/i, null, ctx))
// Postcss
config.module.rules.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
config.module!.rules!.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
// Less
const lessLoader = { loader: 'less-loader', options: options.webpack.loaders.less }
config.module.rules.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
config.module!.rules!.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
// Sass (TODO: optional dependency)
const sassLoader = { loader: 'sass-loader', options: options.webpack.loaders.sass }
config.module.rules.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
config.module!.rules!.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
const scssLoader = { loader: 'sass-loader', options: options.webpack.loaders.scss }
config.module.rules.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
config.module!.rules!.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
// Stylus
const stylusLoader = { loader: 'stylus-loader', options: options.webpack.loaders.stylus }
config.module.rules.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
config.module!.rules!.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
}
function createdStyleRule (lang: string, test: RegExp, processorLoader, ctx: WebpackConfigContext) {
function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx: WebpackConfigContext) {
const { options } = ctx
const styleLoaders = [
@ -90,7 +90,7 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader, ctx: Web
}
}
function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions) {
function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) {
const { options } = ctx
const cssLoader = { loader: 'css-loader', options: cssLoaderOptions }

View File

@ -11,7 +11,7 @@ export function vue (ctx: WebpackConfigContext) {
// @ts-ignore
config.plugins.push(new (VueLoaderPlugin.default || VueLoaderPlugin)())
config.module.rules.push({
config.module!.rules!.push({
test: /\.vue$/i,
loader: 'vue-loader',
options: {
@ -21,12 +21,12 @@ export function vue (ctx: WebpackConfigContext) {
})
if (ctx.isClient) {
config.plugins.push(new VueSSRClientPlugin({
config.plugins!.push(new VueSSRClientPlugin({
filename: resolve(options.buildDir, 'dist/server', `${ctx.name}.manifest.json`),
nuxt: ctx.nuxt
}))
} else {
config.plugins.push(new VueSSRServerPlugin({
config.plugins!.push(new VueSSRServerPlugin({
filename: `${ctx.name}.manifest.json`
}))
}
@ -34,7 +34,7 @@ export function vue (ctx: WebpackConfigContext) {
// Feature flags
// https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
// TODO: Provide options to toggle
config.plugins.push(new webpack.DefinePlugin({
config.plugins!.push(new webpack.DefinePlugin({
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false'
}))

View File

@ -19,7 +19,7 @@ export function createWebpackConfigContext (nuxt: Nuxt) {
isServer: false,
isClient: false,
alias: {} as Configuration['resolve']['alias'],
alias: {} as { [index: string]: string | false | string[] },
transpile: [] as RegExp[]
}
}
@ -40,7 +40,7 @@ export function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigP
export function fileName (ctx: WebpackConfigContext, key: string) {
const { options } = ctx
let fileName = options.webpack.filenames[key]
let fileName = options.webpack.filenames[key as keyof typeof options.webpack.filenames] as ((ctx: WebpackConfigContext) => string) | string
if (typeof fileName === 'function') {
fileName = fileName(ctx)
@ -61,7 +61,7 @@ export function getWebpackConfig (ctx: WebpackConfigContext): Configuration {
// TODO
const builder = {}
const loaders = []
const loaders: any[] = []
// @ts-ignore
const { extend } = options.build

View File

@ -9,7 +9,7 @@ export function createMFS () {
const fs = createFsFromVolume(new Volume())
// Clone to extend
const _fs: Partial<IFs> & { join?(...paths: string[]): string } = { ...fs }
const _fs: IFs & { join?(...paths: string[]): string } = { ...fs } as any
// fs.join method is (still) expected by webpack-dev-middleware
// There might be differences with https://github.com/webpack/memory-fs/blob/master/lib/join.js

View File

@ -35,20 +35,20 @@ export const getPostcssConfig = (nuxt: Nuxt) => {
}
}
function sortPlugins ({ plugins, order }) {
function sortPlugins ({ plugins, order }: any) {
const names = Object.keys(plugins)
if (typeof order === 'string') {
order = orderPresets[order]
order = orderPresets[order as keyof typeof orderPresets]
}
return typeof order === 'function' ? order(names, orderPresets) : (order || names)
}
function loadPlugins (config) {
function loadPlugins (config: any) {
if (!isPureObject(config.plugins)) { return }
// Map postcss plugins into instances on object mode once
const cjs = createCommonJS(import.meta.url)
config.plugins = sortPlugins(config).map((pluginName) => {
config.plugins = sortPlugins(config).map((pluginName: string) => {
const pluginFn = requireModule(pluginName, { paths: [cjs.__dirname] })
const pluginOptions = config.plugins[pluginName]
if (!pluginOptions || typeof pluginFn !== 'function') { return null }
@ -81,9 +81,11 @@ export const getPostcssConfig = (nuxt: Nuxt) => {
loadPlugins(postcssOptions)
}
// @ts-expect-error
delete nuxt.options.webpack.postcss.order
return {
// @ts-expect-error
sourceMap: nuxt.options.webpack.cssSourceMap,
...nuxt.options.webpack.postcss,
postcssOptions

View File

@ -21,6 +21,6 @@ export function registerVirtualModules () {
nuxt.hook('webpack:config', configs => configs.forEach((config) => {
// Support virtual modules (input)
config.plugins.push(virtualModules)
config.plugins!.push(virtualModules)
}))
}

View File

@ -1,7 +1,7 @@
import type { IncomingMessage, ServerResponse } from 'node:http'
import pify from 'pify'
import webpack from 'webpack'
import webpackDevMiddleware, { API } from 'webpack-dev-middleware'
import webpackDevMiddleware, { API, OutputFileSystem } from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import type { Compiler, Watching } from 'webpack'
@ -34,10 +34,10 @@ export async function bundle (nuxt: Nuxt) {
// Configure compilers
const compilers = webpackConfigs.map((config) => {
config.plugins.push(DynamicBasePlugin.webpack({
config.plugins!.push(DynamicBasePlugin.webpack({
sourcemap: nuxt.options.sourcemap
}))
config.plugins.push(composableKeysPlugin.webpack({
config.plugins!.push(composableKeysPlugin.webpack({
sourcemap: nuxt.options.sourcemap,
rootDir: nuxt.options.rootDir
}))
@ -47,7 +47,7 @@ export async function bundle (nuxt: Nuxt) {
// In dev, write files in memory FS
if (nuxt.options.dev) {
compiler.outputFileSystem = mfs
compiler.outputFileSystem = mfs as unknown as OutputFileSystem
}
return compiler
@ -88,7 +88,7 @@ async function createDevMiddleware (compiler: Compiler) {
const hotMiddleware = pify(webpackHotMiddleware(compiler, {
log: false,
heartbeat: 10000,
path: joinURL(nuxt.options.app.baseURL, '__webpack_hmr', compiler.options.name),
path: joinURL(nuxt.options.app.baseURL, '__webpack_hmr', compiler.options.name!),
...hotMiddlewareOptions
}))
@ -96,9 +96,9 @@ async function createDevMiddleware (compiler: Compiler) {
await nuxt.callHook('webpack:hotMiddleware', hotMiddleware)
// Register devMiddleware on server
await nuxt.callHook('server:devMiddleware', async (req, res, next) => {
await nuxt.callHook('server:devMiddleware', async (req: IncomingMessage, res: ServerResponse, next: (error?: any) => void) => {
for (const mw of [devMiddleware, hotMiddleware]) {
await mw?.(req, res)
await mw?.(req, res, next)
}
next()
})
@ -111,11 +111,11 @@ async function compile (compiler: Compiler) {
const { name } = compiler.options
await nuxt.callHook('build:compile', { name, compiler })
await nuxt.callHook('build:compile', { name: name!, compiler })
// Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => {
await nuxt.callHook('build:compiled', { name, compiler, stats })
await nuxt.callHook('build:compiled', { name: name!, compiler, stats })
// Reload renderer
await nuxt.callHook('build:resources', compiler.outputFileSystem)
})
@ -152,7 +152,7 @@ async function compile (compiler: Compiler) {
}
// --- Production Build ---
const stats = await new Promise<webpack.Stats>((resolve, reject) => compiler.run((err, stats) => err ? reject(err) : resolve(stats)))
const stats = await new Promise<webpack.Stats>((resolve, reject) => compiler.run((err, stats) => err ? reject(err) : resolve(stats!)))
if (stats.hasErrors()) {
// non-quiet mode: errors will be printed by webpack itself

View File

@ -3,16 +3,22 @@ import { execSync } from 'node:child_process'
import { resolve } from 'pathe'
import { globby } from 'globby'
interface Dep {
name: string,
range: string,
type: string
}
async function loadPackage (dir: string) {
const pkgPath = resolve(dir, 'package.json')
const data = JSON.parse(await fsp.readFile(pkgPath, 'utf-8').catch(() => '{}'))
const save = () => fsp.writeFile(pkgPath, JSON.stringify(data, null, 2) + '\n')
const updateDeps = (reviver: Function) => {
const updateDeps = (reviver: (dep: Dep) => Dep | void) => {
for (const type of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) {
if (!data[type]) { continue }
for (const e of Object.entries(data[type])) {
const dep = { name: e[0], range: e[1], type }
const dep: Dep = { name: e[0], range: e[1] as string, type }
delete data[type][dep.name]
const updated = reviver(dep) || dep
data[updated.type] = data[updated.type] || {}

View File

@ -350,7 +350,7 @@ describe('extends support', () => {
describe('app', () => {
it('extends foo/app/router.options & bar/app/router.options', async () => {
const html: string = await $fetch('/')
const routerLinkClasses = html.match(/href="\/" class="([^"]*)"/)[1].split(' ')
const routerLinkClasses = html.match(/href="\/" class="([^"]*)"/)?.[1].split(' ')
expect(routerLinkClasses).toContain('foo-active-class')
expect(routerLinkClasses).toContain('bar-exact-active-class')
})
@ -404,7 +404,7 @@ describe('dynamic paths', () => {
}
it('should work with no overrides', async () => {
const html = await $fetch('/assets')
const html: string = await $fetch('/assets')
for (const match of html.matchAll(/(href|src)="(.*?)"/g)) {
const url = match[2]
expect(url.startsWith('/_nuxt/') || url === '/public.svg').toBeTruthy()
@ -417,11 +417,11 @@ describe('dynamic paths', () => {
return
}
const html = await $fetch('/assets')
const html: string = await $fetch('/assets')
const urls = Array.from(html.matchAll(/(href|src)="(.*?)"/g)).map(m => m[2])
const cssURL = urls.find(u => /_nuxt\/assets.*\.css$/.test(u))
expect(cssURL).toBeDefined()
const css = await $fetch(cssURL)
const css: string = await $fetch(cssURL!)
const imageUrls = Array.from(css.matchAll(/url\(([^)]*)\)/g)).map(m => m[1].replace(/[-.][\w]{8}\./g, '.'))
expect(imageUrls).toMatchInlineSnapshot(`
[

View File

@ -4,13 +4,13 @@ import { expect } from 'vitest'
export async function renderPage (path = '/') {
const ctx = useTestContext()
if (!ctx.options.browser) {
return
throw new Error('`renderPage` require `options.browser` to be set')
}
const browser = await getBrowser()
const page = await browser.newPage({})
const pageErrors = []
const consoleLogs = []
const pageErrors: Error[] = []
const consoleLogs: { type:string, text:string }[] = []
page.on('console', (message) => {
consoleLogs.push({
@ -39,7 +39,7 @@ export async function expectNoClientErrors (path: string) {
return
}
const { pageErrors, consoleLogs } = await renderPage(path)
const { pageErrors, consoleLogs } = (await renderPage(path))!
const consoleLogErrors = consoleLogs.filter(i => i.type === 'error')
const consoleLogWarnings = consoleLogs.filter(i => i.type === 'warning')

View File

@ -6,7 +6,8 @@
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"strict": false,
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"noEmit": true,
"noUnusedLocals": true,
@ -33,7 +34,7 @@
}
},
"exclude": [
"**/*/dist/*",
"**/dist/**",
"**/.nuxt/**",
"**/nuxt.d.ts",
"**/examples/**",

View File

@ -327,7 +327,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/standalone@npm:^7.18.11":
"@babel/standalone@npm:^7.18.11, @babel/standalone@npm:^7.18.13":
version: 7.18.13
resolution: "@babel/standalone@npm:7.18.13"
checksum: da010b1ef0d53f7888d01b3ef93aac9a17af5711979e7bc048b80bf08ae6dfa6b637bf92fee0c5753b4ff1bc3639a5b82925f9234d4e2150fc6d4d5c2ccc1f89
@ -1661,7 +1661,7 @@ __metadata:
unbuild: latest
unctx: ^2.0.1
unimport: ^0.6.7
untyped: ^0.4.5
untyped: ^0.4.7
languageName: unknown
linkType: soft
@ -1688,6 +1688,7 @@ __metadata:
ufo: ^0.8.5
unbuild: latest
unimport: ^0.6.7
untyped: ^0.4.7
vite: ~3.0.9
languageName: unknown
linkType: soft
@ -1825,6 +1826,7 @@ __metadata:
"@nuxt/friendly-errors-webpack-plugin": ^2.5.2
"@nuxt/kit": 3.0.0-rc.8
"@nuxt/schema": 3.0.0-rc.8
"@types/lodash-es": ^4.17.6
"@types/pify": ^5.0.1
"@types/webpack-bundle-analyzer": ^4.4.2
"@types/webpack-dev-middleware": ^5.0.2
@ -2280,6 +2282,13 @@ __metadata:
languageName: node
linkType: hard
"@types/flat@npm:^5.0.2":
version: 5.0.2
resolution: "@types/flat@npm:5.0.2"
checksum: e21d51d872e788bdb381887c2880f717ba4377beb4055078136127134858efd15044655610f1fce4832d9a103ded468a25335203fc53f36db08edd5ab5a8b3db
languageName: node
linkType: hard
"@types/fs-extra@npm:^9.0.13":
version: 9.0.13
resolution: "@types/fs-extra@npm:9.0.13"
@ -2331,6 +2340,15 @@ __metadata:
languageName: node
linkType: hard
"@types/lodash-es@npm:^4.17.6":
version: 4.17.6
resolution: "@types/lodash-es@npm:4.17.6"
dependencies:
"@types/lodash": "*"
checksum: 9bd239dd525086e278821949ce12fbdd4f100a060fed9323fc7ad5661113e1641f28a7ebab617230ed3474680d8f4de705c1928b48252bb684be6ec9eed715db
languageName: node
linkType: hard
"@types/lodash.template@npm:^4":
version: 4.5.1
resolution: "@types/lodash.template@npm:4.5.1"
@ -9860,6 +9878,7 @@ __metadata:
"@nuxt/kit": 3.0.0-rc.8
"@nuxt/schema": 3.0.0-rc.8
"@types/clear": ^0
"@types/flat": ^5.0.2
"@types/mri": ^1.1.1
"@types/semver": ^7
c12: ^0.2.9
@ -9976,7 +9995,7 @@ __metadata:
unenv: ^0.6.1
unimport: ^0.6.7
unplugin: ^0.9.2
untyped: ^0.4.5
untyped: ^0.4.7
vue: ^3.2.37
vue-bundle-renderer: ^0.4.2
vue-devtools-stub: ^0.1.0
@ -13190,6 +13209,18 @@ __metadata:
languageName: node
linkType: hard
"untyped@npm:^0.4.7":
version: 0.4.7
resolution: "untyped@npm:0.4.7"
dependencies:
"@babel/core": ^7.18.13
"@babel/standalone": ^7.18.13
"@babel/types": ^7.18.13
scule: ^0.3.2
checksum: d5b189b19e114c4d60e122da9234c68a93d71b312a64bd8303e3aaa96f7a677befa8519ce003dec8cb587ed3e5503046131532196257ed10e647bc741532b1bc
languageName: node
linkType: hard
"upath@npm:^2.0.1":
version: 2.0.1
resolution: "upath@npm:2.0.1"