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 { distDir } from '../dirs'
|
||||
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 }) {
|
||||
// Resolve config
|
||||
@ -339,10 +339,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
nitroConfig.rollupConfig!.plugins!.push(
|
||||
ImportProtectionPlugin.rollup({
|
||||
rootDir: nuxt.options.rootDir,
|
||||
patterns: [
|
||||
...['#app', /^#build(\/|$)/]
|
||||
.map(p => [p, 'Vue app aliases are not allowed in server routes.']) as [RegExp | string, string][]
|
||||
],
|
||||
patterns: nuxtImportProtections(nuxt, { isNitro: true }),
|
||||
exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/]
|
||||
})
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ import importsModule from '../imports/module'
|
||||
/* eslint-enable */
|
||||
import { distDir, pkgDir } from '../dirs'
|
||||
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 { UnctxTransformPlugin } from './plugins/unctx'
|
||||
import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
||||
@ -89,7 +89,7 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
rootDir: nuxt.options.rootDir,
|
||||
// Exclude top-level resolutions by plugins
|
||||
exclude: [join(nuxt.options.rootDir, 'index.html')],
|
||||
patterns: vueAppPatterns(nuxt)
|
||||
patterns: nuxtImportProtections(nuxt)
|
||||
}
|
||||
addVitePlugin(() => ImportProtectionPlugin.vite(config))
|
||||
addWebpackPlugin(() => ImportProtectionPlugin.webpack(config))
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { createRequire } from 'node:module'
|
||||
import { createUnplugin } from 'unplugin'
|
||||
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 type { Nuxt } from 'nuxt/schema'
|
||||
import type { NuxtOptions } from 'nuxt/schema'
|
||||
|
||||
const _require = createRequire(import.meta.url)
|
||||
|
||||
@ -13,16 +13,47 @@ interface ImportProtectionOptions {
|
||||
exclude?: Array<RegExp | string>
|
||||
}
|
||||
|
||||
export const vueAppPatterns = (nuxt: Nuxt) => [
|
||||
[/^(nuxt|nuxt3|nuxt-nightly)$/, '`nuxt`/`nuxt3`/`nuxt-nightly` cannot be imported directly. Instead, import runtime Nuxt composables from `#app` or `#imports`.'],
|
||||
[/^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/, 'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.'],
|
||||
[/(^|node_modules\/)@vue\/composition-api/],
|
||||
...nuxt.options.modules.filter(m => typeof m === 'string').map((m: any) =>
|
||||
[new RegExp(`^${escapeRE(m as string)}$`), 'Importing directly from module entry points is not allowed.']),
|
||||
...[/(^|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.']
|
||||
] as ImportProtectionOptions['patterns']
|
||||
export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: { isNitro?: boolean } = {}) => {
|
||||
const patterns: ImportProtectionOptions['patterns'] = []
|
||||
|
||||
patterns.push([
|
||||
/^(nuxt|nuxt3|nuxt-nightly)$/,
|
||||
'`nuxt`, `nuxt3` or `nuxt-nightly` cannot be imported directly.' + (options.isNitro ? '' : ' Instead, import runtime Nuxt composables from `#app` or `#imports`.')
|
||||
])
|
||||
|
||||
patterns.push([
|
||||
/^((|~|~~|@|@@)\/)?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) {
|
||||
const cache: Record<string, Map<string | RegExp, boolean>> = {}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { normalize } from 'pathe'
|
||||
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 = [
|
||||
['~/nuxt.config', 'app.vue', true],
|
||||
@ -39,13 +40,13 @@ describe('import protection', () => {
|
||||
const transformWithImportProtection = (id: string, importer: string) => {
|
||||
const plugin = ImportProtectionPlugin.rollup({
|
||||
rootDir: '/root',
|
||||
patterns: vueAppPatterns({
|
||||
patterns: nuxtImportProtections({
|
||||
options: {
|
||||
modules: ['some-nuxt-module'],
|
||||
srcDir: 'src/',
|
||||
dir: { server: 'server' }
|
||||
}
|
||||
} as any)
|
||||
srcDir: '/root/src/',
|
||||
serverDir: '/root/src/server'
|
||||
} satisfies Partial<NuxtOptions> as NuxtOptions
|
||||
})
|
||||
})
|
||||
|
||||
return (plugin as any).resolveId(id, importer)
|
||||
|
Loading…
Reference in New Issue
Block a user