mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
fix(nuxt): apply more import protections for nitro runtime (#25162)
This commit is contained in:
parent
58f0627e0b
commit
c4b6560abc
@ -17,7 +17,7 @@ import { template as defaultSpaLoadingTemplate } from '@nuxt/ui-templates/templa
|
|||||||
import { version as nuxtVersion } from '../../package.json'
|
import { version as nuxtVersion } from '../../package.json'
|
||||||
import { distDir } from '../dirs'
|
import { distDir } from '../dirs'
|
||||||
import { toArray } from '../utils'
|
import { toArray } from '../utils'
|
||||||
import { ImportProtectionPlugin } from './plugins/import-protection'
|
import { ImportProtectionPlugin, nuxtImportProtections } from './plugins/import-protection'
|
||||||
|
|
||||||
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||||
// Resolve config
|
// Resolve config
|
||||||
@ -339,10 +339,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
nitroConfig.rollupConfig!.plugins!.push(
|
nitroConfig.rollupConfig!.plugins!.push(
|
||||||
ImportProtectionPlugin.rollup({
|
ImportProtectionPlugin.rollup({
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
patterns: [
|
patterns: nuxtImportProtections(nuxt, { isNitro: true }),
|
||||||
...['#app', /^#build(\/|$)/]
|
|
||||||
.map(p => [p, 'Vue app aliases are not allowed in server routes.']) as [RegExp | string, string][]
|
|
||||||
],
|
|
||||||
exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/]
|
exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ import importsModule from '../imports/module'
|
|||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
import { distDir, pkgDir } from '../dirs'
|
import { distDir, pkgDir } from '../dirs'
|
||||||
import { version } from '../../package.json'
|
import { version } from '../../package.json'
|
||||||
import { ImportProtectionPlugin, vueAppPatterns } from './plugins/import-protection'
|
import { ImportProtectionPlugin, nuxtImportProtections } from './plugins/import-protection'
|
||||||
import type { UnctxTransformPluginOptions } from './plugins/unctx'
|
import type { UnctxTransformPluginOptions } from './plugins/unctx'
|
||||||
import { UnctxTransformPlugin } from './plugins/unctx'
|
import { UnctxTransformPlugin } from './plugins/unctx'
|
||||||
import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
||||||
@ -89,7 +89,7 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
// Exclude top-level resolutions by plugins
|
// Exclude top-level resolutions by plugins
|
||||||
exclude: [join(nuxt.options.rootDir, 'index.html')],
|
exclude: [join(nuxt.options.rootDir, 'index.html')],
|
||||||
patterns: vueAppPatterns(nuxt)
|
patterns: nuxtImportProtections(nuxt)
|
||||||
}
|
}
|
||||||
addVitePlugin(() => ImportProtectionPlugin.vite(config))
|
addVitePlugin(() => ImportProtectionPlugin.vite(config))
|
||||||
addWebpackPlugin(() => ImportProtectionPlugin.webpack(config))
|
addWebpackPlugin(() => ImportProtectionPlugin.webpack(config))
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { createRequire } from 'node:module'
|
import { createRequire } from 'node:module'
|
||||||
import { createUnplugin } from 'unplugin'
|
import { createUnplugin } from 'unplugin'
|
||||||
import { logger } from '@nuxt/kit'
|
import { logger } from '@nuxt/kit'
|
||||||
import { isAbsolute, join, relative } from 'pathe'
|
import { isAbsolute, join, relative, resolve } from 'pathe'
|
||||||
import escapeRE from 'escape-string-regexp'
|
import escapeRE from 'escape-string-regexp'
|
||||||
import type { Nuxt } from 'nuxt/schema'
|
import type { NuxtOptions } from 'nuxt/schema'
|
||||||
|
|
||||||
const _require = createRequire(import.meta.url)
|
const _require = createRequire(import.meta.url)
|
||||||
|
|
||||||
@ -13,16 +13,47 @@ interface ImportProtectionOptions {
|
|||||||
exclude?: Array<RegExp | string>
|
exclude?: Array<RegExp | string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const vueAppPatterns = (nuxt: Nuxt) => [
|
export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: { isNitro?: boolean } = {}) => {
|
||||||
[/^(nuxt|nuxt3|nuxt-nightly)$/, '`nuxt`/`nuxt3`/`nuxt-nightly` cannot be imported directly. Instead, import runtime Nuxt composables from `#app` or `#imports`.'],
|
const patterns: ImportProtectionOptions['patterns'] = []
|
||||||
[/^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/, 'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.'],
|
|
||||||
[/(^|node_modules\/)@vue\/composition-api/],
|
patterns.push([
|
||||||
...nuxt.options.modules.filter(m => typeof m === 'string').map((m: any) =>
|
/^(nuxt|nuxt3|nuxt-nightly)$/,
|
||||||
[new RegExp(`^${escapeRE(m as string)}$`), 'Importing directly from module entry points is not allowed.']),
|
'`nuxt`, `nuxt3` or `nuxt-nightly` cannot be imported directly.' + (options.isNitro ? '' : ' Instead, import runtime Nuxt composables from `#app` or `#imports`.')
|
||||||
...[/(^|node_modules\/)@nuxt\/kit/, /(^|node_modules\/)nuxt\/(config|kit|schema)/, /^nitropack/]
|
])
|
||||||
.map(i => [i, 'This module cannot be imported in the Vue part of your app.']),
|
|
||||||
[new RegExp(escapeRE(join(nuxt.options.srcDir, (nuxt.options.dir as any).server || 'server')) + '\\/(api|routes|middleware|plugins)\\/'), 'Importing from server is not allowed in the Vue part of your app.']
|
patterns.push([
|
||||||
] as ImportProtectionOptions['patterns']
|
/^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/,
|
||||||
|
'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.'
|
||||||
|
])
|
||||||
|
|
||||||
|
patterns.push([/(^|node_modules\/)@vue\/composition-api/])
|
||||||
|
|
||||||
|
for (const mod of nuxt.options.modules.filter(m => typeof m === 'string')) {
|
||||||
|
patterns.push([
|
||||||
|
new RegExp(`^${escapeRE(mod as string)}$`),
|
||||||
|
'Importing directly from module entry-points is not allowed.'
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of [/(^|node_modules\/)@nuxt\/(kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nuxt\/(config|kit|schema)/, 'nitropack']) {
|
||||||
|
patterns.push([i, 'This module cannot be imported' + (options.isNitro ? 'in server runtime.' : ' in the Vue part of your app.')])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.isNitro) {
|
||||||
|
for (const i of ['#app', /^#build(\/|$)/]) {
|
||||||
|
patterns.push([i, 'Vue app aliases are not allowed in server runtime.'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.isNitro) {
|
||||||
|
patterns.push([
|
||||||
|
new RegExp(escapeRE(relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, nuxt.options.serverDir || 'server'))) + '\\/(api|routes|middleware|plugins)\\/'),
|
||||||
|
'Importing from server is not allowed in the Vue part of your app.'
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns
|
||||||
|
}
|
||||||
|
|
||||||
export const ImportProtectionPlugin = createUnplugin(function (options: ImportProtectionOptions) {
|
export const ImportProtectionPlugin = createUnplugin(function (options: ImportProtectionOptions) {
|
||||||
const cache: Record<string, Map<string | RegExp, boolean>> = {}
|
const cache: Record<string, Map<string | RegExp, boolean>> = {}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { normalize } from 'pathe'
|
import { normalize } from 'pathe'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { ImportProtectionPlugin, vueAppPatterns } from '../src/core/plugins/import-protection'
|
import { ImportProtectionPlugin, nuxtImportProtections } from '../src/core/plugins/import-protection'
|
||||||
|
import type { NuxtOptions } from '../schema'
|
||||||
|
|
||||||
const testsToTriggerOn = [
|
const testsToTriggerOn = [
|
||||||
['~/nuxt.config', 'app.vue', true],
|
['~/nuxt.config', 'app.vue', true],
|
||||||
@ -39,13 +40,13 @@ describe('import protection', () => {
|
|||||||
const transformWithImportProtection = (id: string, importer: string) => {
|
const transformWithImportProtection = (id: string, importer: string) => {
|
||||||
const plugin = ImportProtectionPlugin.rollup({
|
const plugin = ImportProtectionPlugin.rollup({
|
||||||
rootDir: '/root',
|
rootDir: '/root',
|
||||||
patterns: vueAppPatterns({
|
patterns: nuxtImportProtections({
|
||||||
options: {
|
options: {
|
||||||
modules: ['some-nuxt-module'],
|
modules: ['some-nuxt-module'],
|
||||||
srcDir: 'src/',
|
srcDir: '/root/src/',
|
||||||
dir: { server: 'server' }
|
serverDir: '/root/src/server'
|
||||||
}
|
} satisfies Partial<NuxtOptions> as NuxtOptions
|
||||||
} as any)
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return (plugin as any).resolveId(id, importer)
|
return (plugin as any).resolveId(id, importer)
|
||||||
|
Loading…
Reference in New Issue
Block a user