mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 07:05:11 +00:00
chore: move bridge to nuxt/bridge
(#4305)
This commit is contained in:
parent
70610d8858
commit
f91f987401
49
.github/ISSUE_TEMPLATE/bug-report-bridge.yml
vendored
49
.github/ISSUE_TEMPLATE/bug-report-bridge.yml
vendored
@ -1,49 +0,0 @@
|
|||||||
name: "\U0001F41E Bug report (Nuxt Bridge)"
|
|
||||||
description: Create a report to help us improve Nuxt Bridge
|
|
||||||
labels: ["pending triage", "bridge"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Please carefully read the contribution docs before creating a bug report
|
|
||||||
👉 https://v3.nuxtjs.org/community/reporting-bugs
|
|
||||||
|
|
||||||
Please use the code sandbox template below to create a minimal reproduction
|
|
||||||
👉 https://codesandbox.io/s/github/nuxt/starter/tree/v2-bridge-codesandbox
|
|
||||||
- type: textarea
|
|
||||||
id: bug-env
|
|
||||||
attributes:
|
|
||||||
label: Environment
|
|
||||||
description: You can use `npx nuxi info` to fill this section
|
|
||||||
placeholder: Environment
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: reproduction
|
|
||||||
attributes:
|
|
||||||
label: Reproduction
|
|
||||||
description: Please provide a link to a repo that can reproduce the problem you ran into. A [minimal reproduction](https://v3.nuxtjs.org/community/reporting-bugs#create-a-minimal-reproduction) is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided after we might close it.
|
|
||||||
placeholder: Reproduction
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: bug-description
|
|
||||||
attributes:
|
|
||||||
label: Describe the bug
|
|
||||||
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
|
|
||||||
placeholder: Bug description
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: additonal
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: If applicable, add any other context about the problem here`
|
|
||||||
- type: textarea
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: Logs
|
|
||||||
description: |
|
|
||||||
Optional if provided reproduction. Please try not to insert an image but copy paste the log text.
|
|
||||||
render: shell
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
name: "\U0001F41E Bug report (Nuxt 3)"
|
name: "\U0001F41E Bug report"
|
||||||
description: Create a report to help us improve Nuxt 3
|
description: Create a report to help us improve Nuxt
|
||||||
labels: ["pending triage", "nuxt3"]
|
labels: ["pending triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
@ -1,5 +0,0 @@
|
|||||||
# Nuxt Bridge
|
|
||||||
|
|
||||||
> Use backported Nuxt 3 features in Nuxt 2
|
|
||||||
|
|
||||||
Learn more about this package: <https://v3.nuxtjs.org/bridge/overview>
|
|
@ -1,2 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
import 'nuxi/cli'
|
|
@ -1,14 +0,0 @@
|
|||||||
import { defineBuildConfig } from 'unbuild'
|
|
||||||
|
|
||||||
export default defineBuildConfig({
|
|
||||||
declaration: true,
|
|
||||||
entries: [
|
|
||||||
'src/module',
|
|
||||||
{ input: 'src/runtime/', outDir: 'dist/runtime', format: 'esm', declaration: true }
|
|
||||||
],
|
|
||||||
externals: [
|
|
||||||
'webpack',
|
|
||||||
'vite',
|
|
||||||
'vue-meta'
|
|
||||||
]
|
|
||||||
})
|
|
@ -1,27 +0,0 @@
|
|||||||
// CommonJS proxy to bypass jiti transforms from nuxt 2
|
|
||||||
module.exports = function (...args) {
|
|
||||||
return import('./dist/module.mjs').then(m => m.default.call(this, ...args))
|
|
||||||
}
|
|
||||||
|
|
||||||
const pkg = require('./package.json')
|
|
||||||
|
|
||||||
module.exports.defineNuxtConfig = (config = {}) => {
|
|
||||||
if (config.bridge !== false) {
|
|
||||||
config.bridge = config.bridge || {}
|
|
||||||
config.bridge._version = pkg.version
|
|
||||||
if (!config.buildModules) {
|
|
||||||
config.buildModules = []
|
|
||||||
}
|
|
||||||
if (!config.buildModules.find(m => m === '@nuxt/bridge' || m === '@nuxt/bridge-edge')) {
|
|
||||||
// Ensure other modules register their hooks before
|
|
||||||
config.buildModules.push('@nuxt/bridge')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.meta = {
|
|
||||||
pkg,
|
|
||||||
name: pkg.name,
|
|
||||||
version: pkg.version
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@nuxt/bridge",
|
|
||||||
"version": "3.0.0",
|
|
||||||
"repository": "nuxt/framework",
|
|
||||||
"license": "MIT",
|
|
||||||
"type": "module",
|
|
||||||
"main": "./module.cjs",
|
|
||||||
"types": "./types.d.ts",
|
|
||||||
"files": [
|
|
||||||
"module.cjs",
|
|
||||||
"types.d.ts",
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"bin": {
|
|
||||||
"nuxi": "./bin/nuxt.mjs"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"prepack": "unbuild"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
|
||||||
"@babel/plugin-transform-typescript": "^7.16.8",
|
|
||||||
"@nuxt/kit": "3.0.0",
|
|
||||||
"@nuxt/postcss8": "^1.1.3",
|
|
||||||
"@nuxt/schema": "3.0.0",
|
|
||||||
"@nuxt/ui-templates": "npm:@nuxt/ui-templates-edge@latest",
|
|
||||||
"@vitejs/plugin-legacy": "^1.8.0",
|
|
||||||
"@vue/composition-api": "^1.4.9",
|
|
||||||
"acorn": "^8.7.0",
|
|
||||||
"cookie-es": "^0.5.0",
|
|
||||||
"defu": "^6.0.0",
|
|
||||||
"destr": "^1.1.1",
|
|
||||||
"enhanced-resolve": "^5.9.3",
|
|
||||||
"escape-string-regexp": "^5.0.0",
|
|
||||||
"estree-walker": "^3.0.1",
|
|
||||||
"externality": "^0.2.1",
|
|
||||||
"fs-extra": "^10.0.1",
|
|
||||||
"get-port-please": "^2.5.0",
|
|
||||||
"globby": "^13.1.1",
|
|
||||||
"h3": "^0.7.3",
|
|
||||||
"hash-sum": "^2.0.0",
|
|
||||||
"knitwork": "^0.1.1",
|
|
||||||
"magic-string": "^0.26.1",
|
|
||||||
"mlly": "^0.5.1",
|
|
||||||
"murmurhash-es": "^0.1.1",
|
|
||||||
"nitropack": "^0.2.7",
|
|
||||||
"node-fetch": "^3.2.3",
|
|
||||||
"nuxi": "3.0.0",
|
|
||||||
"ohash": "^0.1.0",
|
|
||||||
"pathe": "^0.2.0",
|
|
||||||
"perfect-debounce": "^0.1.3",
|
|
||||||
"postcss": "^8",
|
|
||||||
"postcss-import": "^14.1.0",
|
|
||||||
"postcss-import-resolver": "^2.0.0",
|
|
||||||
"postcss-preset-env": "^7.4.3",
|
|
||||||
"postcss-url": "^10.1.3",
|
|
||||||
"scule": "^0.2.1",
|
|
||||||
"semver": "^7.3.7",
|
|
||||||
"ufo": "^0.8.3",
|
|
||||||
"unimport": "^0.1.4",
|
|
||||||
"unplugin": "^0.6.1",
|
|
||||||
"unplugin-vue2-script-setup": "^0.10.2",
|
|
||||||
"untyped": "^0.4.4",
|
|
||||||
"vite": "^2.9.1",
|
|
||||||
"vite-plugin-vue2": "^1.9.3",
|
|
||||||
"vue-bundle-renderer": "^0.3.5",
|
|
||||||
"vue-template-compiler": "^2.6.14"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@nuxt/types": "^2.15.8",
|
|
||||||
"@types/fs-extra": "^9.0.13",
|
|
||||||
"@types/hash-sum": "^1.0.0",
|
|
||||||
"@types/node-fetch": "^3.0.2",
|
|
||||||
"@vueuse/head": "^0.7.6",
|
|
||||||
"nuxt": "^2",
|
|
||||||
"unbuild": "latest",
|
|
||||||
"vue": "^2",
|
|
||||||
"vue-router": "^3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^14.16.0 || ^16.11.0 || ^17.0.0"
|
|
||||||
},
|
|
||||||
"installConfig": {
|
|
||||||
"hoistingLimits": "workspaces"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
import { useNuxt, addTemplate, resolveAlias, addWebpackPlugin, addVitePlugin, addPlugin } from '@nuxt/kit'
|
|
||||||
import { NuxtModule } from '@nuxt/schema'
|
|
||||||
import { resolve } from 'pathe'
|
|
||||||
import { componentsTypeTemplate } from '../../nuxt3/src/components/templates'
|
|
||||||
import { schemaTemplate } from '../../nuxt3/src/core/templates'
|
|
||||||
import { distDir } from './dirs'
|
|
||||||
import { VueCompat } from './vue-compat'
|
|
||||||
|
|
||||||
export function setupAppBridge (_options: any) {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
// Setup aliases
|
|
||||||
nuxt.options.alias['#app'] = resolve(distDir, 'runtime/index')
|
|
||||||
nuxt.options.alias['nuxt3/app'] = nuxt.options.alias['#app']
|
|
||||||
nuxt.options.alias['nuxt/app'] = nuxt.options.alias['#app']
|
|
||||||
nuxt.options.alias['#build'] = nuxt.options.buildDir
|
|
||||||
|
|
||||||
// Mock `bundleBuilder.build` to support `nuxi prepare`
|
|
||||||
if (nuxt.options._prepare) {
|
|
||||||
nuxt.hook('builder:prepared', (builder) => {
|
|
||||||
builder.bundleBuilder.build = () => Promise.resolve(builder.bundleBuilder)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transpile core vue libraries
|
|
||||||
// TODO: resolve in vercel/nft
|
|
||||||
nuxt.options.build.transpile.push('vuex')
|
|
||||||
|
|
||||||
// Transpile libs with modern syntax
|
|
||||||
nuxt.options.build.transpile.push('h3')
|
|
||||||
|
|
||||||
// Disable legacy fetch polyfills
|
|
||||||
nuxt.options.fetch.server = false
|
|
||||||
nuxt.options.fetch.client = false
|
|
||||||
|
|
||||||
// Setup types for components
|
|
||||||
const components = []
|
|
||||||
nuxt.hook('components:extend', (registeredComponents) => {
|
|
||||||
components.push(...registeredComponents)
|
|
||||||
})
|
|
||||||
addTemplate({
|
|
||||||
...componentsTypeTemplate,
|
|
||||||
options: { components, buildDir: nuxt.options.buildDir }
|
|
||||||
})
|
|
||||||
nuxt.hook('prepare:types', ({ references }) => {
|
|
||||||
references.push({ path: resolve(nuxt.options.buildDir, 'types/components.d.ts') })
|
|
||||||
})
|
|
||||||
|
|
||||||
// Augment schema with module types
|
|
||||||
nuxt.hook('modules:done', async (container: any) => {
|
|
||||||
nuxt.options._installedModules = await Promise.all(Object.values(container.requiredModules).map(async (m: { src: string, handler: NuxtModule }) => ({
|
|
||||||
meta: await m.handler.getMeta?.(),
|
|
||||||
entryPath: resolveAlias(m.src, nuxt.options.alias)
|
|
||||||
})))
|
|
||||||
addTemplate(schemaTemplate)
|
|
||||||
})
|
|
||||||
nuxt.hook('prepare:types', ({ references }) => {
|
|
||||||
// Add module augmentations directly to NuxtConfig
|
|
||||||
references.push({ path: resolve(nuxt.options.buildDir, 'types/schema.d.ts') })
|
|
||||||
})
|
|
||||||
|
|
||||||
// Alias vue to have identical vue3 exports
|
|
||||||
const { dst: vueCompat } = addTemplate({ src: resolve(distDir, 'runtime/vue2-bridge.mjs') })
|
|
||||||
addWebpackPlugin(VueCompat.webpack({ src: vueCompat }))
|
|
||||||
addVitePlugin(VueCompat.vite({ src: vueCompat }))
|
|
||||||
|
|
||||||
nuxt.hook('prepare:types', ({ tsConfig, references }) => {
|
|
||||||
// Type 'vue' module with composition API exports
|
|
||||||
references.push({ path: resolve(distDir, 'runtime/vue2-bridge.d.ts') })
|
|
||||||
|
|
||||||
// Enable Volar support with vue 2 compat mode
|
|
||||||
// @ts-ignore
|
|
||||||
tsConfig.vueCompilerOptions = {
|
|
||||||
experimentalCompatMode: 2
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deprecate various Nuxt options
|
|
||||||
if (nuxt.options.globalName !== 'nuxt') {
|
|
||||||
throw new Error('Custom global name is not supported by @nuxt/bridge.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix wp4 esm
|
|
||||||
nuxt.hook('webpack:config', (configs) => {
|
|
||||||
for (const config of configs.filter(c => c.module)) {
|
|
||||||
// @ts-ignore
|
|
||||||
const jsRule: any = config.module.rules.find(rule => rule.test instanceof RegExp && rule.test.test('index.mjs'))
|
|
||||||
jsRule.type = 'javascript/auto'
|
|
||||||
|
|
||||||
config.module.rules.unshift({
|
|
||||||
test: /\.mjs$/,
|
|
||||||
type: 'javascript/auto',
|
|
||||||
include: [/node_modules/]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
addPlugin({
|
|
||||||
src: resolve(distDir, 'runtime/error.plugin.server.mjs'),
|
|
||||||
mode: 'server'
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
// Based on https://github.com/webpack/webpack/blob/v4.46.0/lib/node/NodeMainTemplatePlugin.js#L81-L191
|
|
||||||
|
|
||||||
import { createRequire } from 'module'
|
|
||||||
import type { Compiler } from 'webpack'
|
|
||||||
export class AsyncLoadingPlugin {
|
|
||||||
private opts: any
|
|
||||||
private Template: any
|
|
||||||
constructor (opts) {
|
|
||||||
this.opts = opts
|
|
||||||
const _require = createRequire(import.meta.url)
|
|
||||||
const TemplatePath = _require.resolve('webpack/lib/Template', { paths: [...this.opts.modulesDir] })
|
|
||||||
this.Template = _require(TemplatePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
apply (compiler: Compiler) {
|
|
||||||
compiler.hooks.compilation.tap('AsyncLoading', (compilation) => {
|
|
||||||
const mainTemplate = compilation.mainTemplate
|
|
||||||
mainTemplate.hooks.requireEnsure.tap(
|
|
||||||
'AsyncLoading',
|
|
||||||
(_source, chunk, hash) => {
|
|
||||||
const Template = this.Template
|
|
||||||
const chunkFilename = mainTemplate.outputOptions.chunkFilename
|
|
||||||
const chunkMaps = chunk.getChunkMaps()
|
|
||||||
const insertMoreModules = [
|
|
||||||
'var moreModules = chunk.modules, chunkIds = chunk.ids;',
|
|
||||||
'for(var moduleId in moreModules) {',
|
|
||||||
Template.indent(
|
|
||||||
mainTemplate.renderAddModule(
|
|
||||||
hash,
|
|
||||||
chunk,
|
|
||||||
'moduleId',
|
|
||||||
'moreModules[moduleId]'
|
|
||||||
)
|
|
||||||
),
|
|
||||||
'}'
|
|
||||||
]
|
|
||||||
return Template.asString([
|
|
||||||
'// Async chunk loading for Nitro',
|
|
||||||
'',
|
|
||||||
'var installedChunkData = installedChunks[chunkId];',
|
|
||||||
'if(installedChunkData !== 0) { // 0 means "already installed".',
|
|
||||||
Template.indent([
|
|
||||||
'// array of [resolve, reject, promise] means "currently loading"',
|
|
||||||
'if(installedChunkData) {',
|
|
||||||
Template.indent(['promises.push(installedChunkData[2]);']),
|
|
||||||
'} else {',
|
|
||||||
Template.indent([
|
|
||||||
'// load the chunk and return promise to it',
|
|
||||||
'var promise = new Promise(function(resolve, reject) {',
|
|
||||||
Template.indent([
|
|
||||||
'installedChunkData = installedChunks[chunkId] = [resolve, reject];',
|
|
||||||
'import(' +
|
|
||||||
mainTemplate.getAssetPath(
|
|
||||||
JSON.stringify(`./${chunkFilename}`),
|
|
||||||
{
|
|
||||||
hash: `" + ${mainTemplate.renderCurrentHashCode(
|
|
||||||
hash
|
|
||||||
)} + "`,
|
|
||||||
hashWithLength: length =>
|
|
||||||
`" + ${mainTemplate.renderCurrentHashCode(
|
|
||||||
hash,
|
|
||||||
length
|
|
||||||
)} + "`,
|
|
||||||
chunk: {
|
|
||||||
id: '" + chunkId + "',
|
|
||||||
hash: `" + ${JSON.stringify(
|
|
||||||
chunkMaps.hash
|
|
||||||
)}[chunkId] + "`,
|
|
||||||
hashWithLength: (length) => {
|
|
||||||
const shortChunkHashMap = {}
|
|
||||||
for (const chunkId of Object.keys(chunkMaps.hash)) {
|
|
||||||
if (typeof chunkMaps.hash[chunkId] === 'string') {
|
|
||||||
shortChunkHashMap[chunkId] = chunkMaps.hash[
|
|
||||||
chunkId
|
|
||||||
].substr(0, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `" + ${JSON.stringify(
|
|
||||||
shortChunkHashMap
|
|
||||||
)}[chunkId] + "`
|
|
||||||
},
|
|
||||||
contentHash: {
|
|
||||||
javascript: `" + ${JSON.stringify(
|
|
||||||
chunkMaps.contentHash.javascript
|
|
||||||
)}[chunkId] + "`
|
|
||||||
},
|
|
||||||
contentHashWithLength: {
|
|
||||||
javascript: (length) => {
|
|
||||||
const shortContentHashMap = {}
|
|
||||||
const contentHash =
|
|
||||||
chunkMaps.contentHash.javascript
|
|
||||||
for (const chunkId of Object.keys(contentHash)) {
|
|
||||||
if (typeof contentHash[chunkId] === 'string') {
|
|
||||||
shortContentHashMap[chunkId] = contentHash[
|
|
||||||
chunkId
|
|
||||||
].substr(0, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `" + ${JSON.stringify(
|
|
||||||
shortContentHashMap
|
|
||||||
)}[chunkId] + "`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
name: `" + (${JSON.stringify(
|
|
||||||
chunkMaps.name
|
|
||||||
)}[chunkId]||chunkId) + "`
|
|
||||||
},
|
|
||||||
contentHashType: 'javascript'
|
|
||||||
}
|
|
||||||
) +
|
|
||||||
').then(chunk => {',
|
|
||||||
Template.indent(
|
|
||||||
insertMoreModules
|
|
||||||
.concat([
|
|
||||||
'var callbacks = [];',
|
|
||||||
'for(var i = 0; i < chunkIds.length; i++) {',
|
|
||||||
Template.indent([
|
|
||||||
'if(installedChunks[chunkIds[i]])',
|
|
||||||
Template.indent([
|
|
||||||
'callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);'
|
|
||||||
]),
|
|
||||||
'installedChunks[chunkIds[i]] = 0;'
|
|
||||||
]),
|
|
||||||
'}',
|
|
||||||
'for(i = 0; i < callbacks.length; i++)',
|
|
||||||
Template.indent('callbacks[i]();')
|
|
||||||
])
|
|
||||||
),
|
|
||||||
'});'
|
|
||||||
]),
|
|
||||||
'});',
|
|
||||||
'promises.push(installedChunkData[2] = promise);'
|
|
||||||
]),
|
|
||||||
'}'
|
|
||||||
]),
|
|
||||||
'}'
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import { installModule, useNuxt } from '@nuxt/kit'
|
|
||||||
import * as CompositionApi from '@vue/composition-api'
|
|
||||||
import type { Preset } from 'unimport'
|
|
||||||
import autoImports from '../../nuxt3/src/auto-imports/module'
|
|
||||||
import { vuePreset } from '../../nuxt3/src/auto-imports/presets'
|
|
||||||
|
|
||||||
const UnsupportedImports = new Set(['useAsyncData', 'useFetch', 'useError', 'throwError', 'clearError', 'defineNuxtLink', 'useActiveRoute'])
|
|
||||||
const CapiHelpers = new Set(Object.keys(CompositionApi))
|
|
||||||
|
|
||||||
export function setupAutoImports () {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
const bridgePresets: Preset[] = [{
|
|
||||||
from: '@vue/composition-api',
|
|
||||||
imports: vuePreset.imports.filter(i => CapiHelpers.has(i as string))
|
|
||||||
}]
|
|
||||||
|
|
||||||
nuxt.hook('autoImports:sources', (presets) => {
|
|
||||||
const vuePreset = presets.find(p => p.from === 'vue')
|
|
||||||
if (vuePreset) { vuePreset.disabled = true }
|
|
||||||
|
|
||||||
const appPreset = presets.find(p => p.from === '#app')
|
|
||||||
if (!appPreset) { return }
|
|
||||||
|
|
||||||
for (const [index, i] of Object.entries(appPreset.imports).reverse()) {
|
|
||||||
if (typeof i === 'string' && UnsupportedImports.has(i)) {
|
|
||||||
appPreset.imports.splice(Number(index), 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appPreset.imports.push('useNuxt2Meta')
|
|
||||||
})
|
|
||||||
|
|
||||||
nuxt.hook('modules:done', () => installModule(autoImports, { presets: bridgePresets }))
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
import crypto from 'crypto'
|
|
||||||
import { pathToFileURL } from 'url'
|
|
||||||
import { createUnplugin } from 'unplugin'
|
|
||||||
import { parse } from 'acorn'
|
|
||||||
import MagicString from 'magic-string'
|
|
||||||
import { walk } from 'estree-walker'
|
|
||||||
import { parseQuery, parseURL } from 'ufo'
|
|
||||||
|
|
||||||
function createKey (
|
|
||||||
source: string,
|
|
||||||
method: crypto.BinaryToTextEncoding = 'base64'
|
|
||||||
) {
|
|
||||||
const hash = crypto.createHash('md5')
|
|
||||||
hash.update(source)
|
|
||||||
return hash.digest(method).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyedFunctions =
|
|
||||||
/(useStatic|shallowSsrRef|ssrPromise|ssrRef|reqSsrRef|useAsync)/
|
|
||||||
|
|
||||||
export const KeyPlugin = createUnplugin(() => {
|
|
||||||
return {
|
|
||||||
name: 'nuxt-legacy-capi-key-transform',
|
|
||||||
enforce: 'pre',
|
|
||||||
transformInclude (id) {
|
|
||||||
const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href))
|
|
||||||
const query = parseQuery(search)
|
|
||||||
|
|
||||||
if (id.includes('node_modules')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// vue files
|
|
||||||
if (pathname.endsWith('.vue') && (query.type === 'script' || !search)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// js files
|
|
||||||
if (pathname.match(/\.((c|m)?j|t)sx?/g)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
transform (code, id) {
|
|
||||||
if (!keyedFunctions.test(code)) { return null }
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { 0: script = code, index: codeIndex = 0 } =
|
|
||||||
code.match(/(?<=<script[^>]*>)[\S\s.]*?(?=<\/script>)/) || []
|
|
||||||
const ast = parse(script, { ecmaVersion: 2020, sourceType: 'module' })
|
|
||||||
const s = new MagicString(code)
|
|
||||||
|
|
||||||
walk(ast, {
|
|
||||||
enter (node) {
|
|
||||||
const { end } = node as unknown as {
|
|
||||||
end: number
|
|
||||||
}
|
|
||||||
const { callee, arguments: args = [] } = node as {
|
|
||||||
callee?: {
|
|
||||||
type?: string
|
|
||||||
name?: string
|
|
||||||
property?: { type: string; name: string }
|
|
||||||
}
|
|
||||||
arguments?: any[]
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
callee?.type === 'Identifier' ||
|
|
||||||
callee?.property?.type === 'Identifier'
|
|
||||||
) {
|
|
||||||
let method: crypto.BinaryToTextEncoding = 'base64'
|
|
||||||
|
|
||||||
switch (callee.name || callee.property?.name) {
|
|
||||||
case 'useStatic':
|
|
||||||
if (args.length > 2) { return }
|
|
||||||
if (args.length === 2) {
|
|
||||||
s.prependLeft(codeIndex + end - 1, ', undefined')
|
|
||||||
}
|
|
||||||
method = 'hex'
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'shallowSsrRef':
|
|
||||||
case 'ssrPromise':
|
|
||||||
case 'ssrRef':
|
|
||||||
case 'reqSsrRef':
|
|
||||||
case 'useAsync':
|
|
||||||
if (args.length > 1) { return }
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.appendLeft(
|
|
||||||
codeIndex + end - 1,
|
|
||||||
", '" + createKey(`${id}-${end}`, method) + "'"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return s.toString()
|
|
||||||
} catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,54 +0,0 @@
|
|||||||
import { createRequire } from 'module'
|
|
||||||
import { useNuxt, addPluginTemplate, addVitePlugin, addWebpackPlugin } from '@nuxt/kit'
|
|
||||||
import { resolve } from 'pathe'
|
|
||||||
import { BridgeConfig } from '../types'
|
|
||||||
import { distDir } from './dirs'
|
|
||||||
import { KeyPlugin } from './capi-legacy-key-plugin'
|
|
||||||
|
|
||||||
export function setupCAPIBridge (options: Exclude<BridgeConfig['capi'], boolean>) {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
// Error if `@nuxtjs/composition-api` is added
|
|
||||||
if (nuxt.options.buildModules.find(m => m === '@nuxtjs/composition-api' || m === '@nuxtjs/composition-api/module')) {
|
|
||||||
throw new Error('Please remove `@nuxtjs/composition-api` from `buildModules` to avoid conflict with bridge.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add composition-api support
|
|
||||||
const _require = createRequire(import.meta.url)
|
|
||||||
const vueCapiEntry = _require.resolve('@vue/composition-api/dist/vue-composition-api.mjs')
|
|
||||||
nuxt.options.alias['@vue/composition-api/dist/vue-composition-api.common.js'] = vueCapiEntry
|
|
||||||
nuxt.options.alias['@vue/composition-api/dist/vue-composition-api.common.prod.js'] = vueCapiEntry
|
|
||||||
nuxt.options.alias['@vue/composition-api/dist/vue-composition-api.esm.js'] = vueCapiEntry
|
|
||||||
nuxt.options.alias['@vue/composition-api/dist/vue-composition-api.js'] = vueCapiEntry
|
|
||||||
nuxt.options.alias['@vue/composition-api/dist/vue-composition-api.mjs'] = vueCapiEntry
|
|
||||||
nuxt.options.alias['@vue/composition-api'] = vueCapiEntry
|
|
||||||
const capiPluginPath = resolve(distDir, 'runtime/capi.plugin.mjs')
|
|
||||||
addPluginTemplate({ filename: 'capi.plugin.mjs', src: capiPluginPath })
|
|
||||||
|
|
||||||
// Add support for useNuxtApp
|
|
||||||
const appPlugin = addPluginTemplate(resolve(distDir, 'runtime/app.plugin.mjs'))
|
|
||||||
nuxt.hook('modules:done', () => {
|
|
||||||
nuxt.options.plugins.unshift(appPlugin)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Register Composition API before loading the rest of app
|
|
||||||
nuxt.hook('webpack:config', (configs) => {
|
|
||||||
// @ts-ignore
|
|
||||||
configs.forEach(config => config.entry.app.unshift(capiPluginPath))
|
|
||||||
})
|
|
||||||
|
|
||||||
if (options.legacy === false) {
|
|
||||||
// Skip adding `@nuxtjs/composition-api` handlers if legacy support is disabled
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle legacy `@nuxtjs/composition-api`
|
|
||||||
nuxt.options.alias['@nuxtjs/composition-api'] = resolve(distDir, 'runtime/capi.legacy.mjs')
|
|
||||||
nuxt.options.build.transpile.push('@nuxtjs/composition-api', '@vue/composition-api')
|
|
||||||
|
|
||||||
// Enable automatic ssrRef key generation
|
|
||||||
addVitePlugin(KeyPlugin.vite())
|
|
||||||
addWebpackPlugin(KeyPlugin.webpack())
|
|
||||||
|
|
||||||
// TODO: Add @nuxtjs/composition-api shims
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { fileURLToPath } from 'url'
|
|
||||||
import { existsSync } from 'fs'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { dirname } from 'pathe'
|
|
||||||
|
|
||||||
let dir = dirname(fileURLToPath(import.meta.url))
|
|
||||||
while (dir !== '/' && !existsSync(join(dir, 'package.json'))) {
|
|
||||||
dir = dirname(dir)
|
|
||||||
}
|
|
||||||
export const pkgDir = dir
|
|
||||||
export const distDir = join(pkgDir, 'dist')
|
|
@ -1,33 +0,0 @@
|
|||||||
import { resolve } from 'pathe'
|
|
||||||
import { addTemplate, useNuxt, installModule } from '@nuxt/kit'
|
|
||||||
import metaModule from '../../nuxt3/src/head/module'
|
|
||||||
import { distDir } from './dirs'
|
|
||||||
|
|
||||||
const checkDocsMsg = 'Please see https://v3.nuxtjs.org for more information.'
|
|
||||||
const msgPrefix = '[bridge] [meta]'
|
|
||||||
|
|
||||||
interface SetupMetaOptions {
|
|
||||||
needsExplicitEnable?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setupMeta = async (opts: SetupMetaOptions) => {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
if (opts.needsExplicitEnable) {
|
|
||||||
const metaPath = addTemplate({
|
|
||||||
filename: 'meta.mjs',
|
|
||||||
getContents: () => `export const useHead = () => console.warn('${msgPrefix} To enable experimental \`useHead\` support, set \`bridge.meta\` to \`true\` in your \`nuxt.config\`. ${checkDocsMsg}')`
|
|
||||||
})
|
|
||||||
nuxt.options.alias['#head'] = metaPath.dst
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nuxt.options.head && typeof nuxt.options.head === 'function') {
|
|
||||||
throw new TypeError(`${msgPrefix} The head() function in \`nuxt.config\` has been deprecated and in Nuxt 3 will need to be moved to \`app.vue\`. ${checkDocsMsg}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const runtimeDir = resolve(distDir, 'runtime/head')
|
|
||||||
nuxt.options.alias['#head'] = runtimeDir
|
|
||||||
|
|
||||||
await installModule(metaModule)
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
import { createRequire } from 'module'
|
|
||||||
import { defineNuxtModule, installModule, checkNuxtCompatibility, nuxtCtx } from '@nuxt/kit'
|
|
||||||
import type { NuxtModule } from '@nuxt/schema'
|
|
||||||
import { NuxtCompatibility } from '@nuxt/schema/src/types/compatibility'
|
|
||||||
import type { BridgeConfig, ScriptSetupOptions } from '../types'
|
|
||||||
import { setupNitroBridge } from './nitro'
|
|
||||||
import { setupAppBridge } from './app'
|
|
||||||
import { setupCAPIBridge } from './capi'
|
|
||||||
import { setupBetterResolve } from './resolve'
|
|
||||||
import { setupAutoImports } from './auto-imports'
|
|
||||||
import { setupTypescript } from './typescript'
|
|
||||||
import { setupMeta } from './meta'
|
|
||||||
import { setupTranspile } from './transpile'
|
|
||||||
import { setupScriptSetup } from './setup'
|
|
||||||
|
|
||||||
export default defineNuxtModule({
|
|
||||||
meta: {
|
|
||||||
name: 'nuxt-bridge',
|
|
||||||
configKey: 'bridge'
|
|
||||||
},
|
|
||||||
defaults: {
|
|
||||||
nitro: true,
|
|
||||||
vite: false,
|
|
||||||
app: {},
|
|
||||||
capi: {},
|
|
||||||
transpile: true,
|
|
||||||
scriptSetup: true,
|
|
||||||
autoImports: true,
|
|
||||||
compatibility: true,
|
|
||||||
meta: null,
|
|
||||||
// TODO: Remove from 2.16
|
|
||||||
postcss8: true,
|
|
||||||
typescript: true,
|
|
||||||
resolve: true
|
|
||||||
} as BridgeConfig,
|
|
||||||
async setup (opts, nuxt) {
|
|
||||||
const _require = createRequire(import.meta.url)
|
|
||||||
|
|
||||||
// Allow using kit compasables in all modules
|
|
||||||
if (!nuxtCtx.use()) {
|
|
||||||
nuxtCtx.set(nuxt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mock _layers
|
|
||||||
nuxt.options._layers = nuxt.options._layers || [{
|
|
||||||
config: nuxt.options,
|
|
||||||
cwd: nuxt.options.rootDir,
|
|
||||||
configFile: nuxt.options._nuxtConfigFile
|
|
||||||
}]
|
|
||||||
|
|
||||||
if (opts.nitro) {
|
|
||||||
nuxt.hook('modules:done', async () => {
|
|
||||||
await setupNitroBridge()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (opts.app) {
|
|
||||||
await setupAppBridge(opts.app)
|
|
||||||
}
|
|
||||||
if (opts.capi) {
|
|
||||||
if (!opts.app) {
|
|
||||||
throw new Error('[bridge] Cannot enable composition-api with app disabled!')
|
|
||||||
}
|
|
||||||
await setupCAPIBridge(opts.capi === true ? {} : opts.capi)
|
|
||||||
}
|
|
||||||
if (opts.scriptSetup) {
|
|
||||||
await setupScriptSetup(opts.scriptSetup as ScriptSetupOptions)
|
|
||||||
}
|
|
||||||
if (opts.autoImports) {
|
|
||||||
await setupAutoImports()
|
|
||||||
}
|
|
||||||
if (opts.vite) {
|
|
||||||
const viteModule = await import('./vite/module').then(r => r.default || r) as NuxtModule
|
|
||||||
nuxt.hook('modules:done', () => installModule(viteModule))
|
|
||||||
}
|
|
||||||
if (opts.postcss8) {
|
|
||||||
await installModule(_require.resolve('@nuxt/postcss8'))
|
|
||||||
}
|
|
||||||
if (opts.typescript) {
|
|
||||||
await setupTypescript()
|
|
||||||
}
|
|
||||||
if (opts.resolve) {
|
|
||||||
setupBetterResolve()
|
|
||||||
}
|
|
||||||
if (opts.transpile) {
|
|
||||||
setupTranspile()
|
|
||||||
}
|
|
||||||
if (opts.compatibility) {
|
|
||||||
nuxt.hook('modules:done', async (moduleContainer: any) => {
|
|
||||||
for (const [name, m] of Object.entries(moduleContainer.requiredModules || {})) {
|
|
||||||
const compat = ((m as any)?.handler?.meta?.compatibility || {}) as NuxtCompatibility
|
|
||||||
if (compat) {
|
|
||||||
const issues = await checkNuxtCompatibility(compat, nuxt)
|
|
||||||
if (issues.length) {
|
|
||||||
console.warn(`[bridge] Detected module incompatibility issues for \`${name}\`:\n` + issues.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (opts.meta !== false && opts.capi) {
|
|
||||||
await setupMeta({ needsExplicitEnable: opts.meta === null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,396 +0,0 @@
|
|||||||
import { promises as fsp, existsSync } from 'fs'
|
|
||||||
import fetch from 'node-fetch'
|
|
||||||
import fsExtra from 'fs-extra'
|
|
||||||
import { addPluginTemplate, resolvePath, useNuxt } from '@nuxt/kit'
|
|
||||||
import { joinURL, stringifyQuery, withoutTrailingSlash } from 'ufo'
|
|
||||||
import { resolve, join, dirname } from 'pathe'
|
|
||||||
import { createNitro, createDevServer, build, writeTypes, prepare, copyPublicAssets, prerender } from 'nitropack'
|
|
||||||
import { dynamicEventHandler, toEventHandler } from 'h3'
|
|
||||||
import type { Nitro, NitroEventHandler, NitroDevEventHandler, NitroConfig } from 'nitropack'
|
|
||||||
import { Nuxt } from '@nuxt/schema'
|
|
||||||
import defu from 'defu'
|
|
||||||
import { AsyncLoadingPlugin } from './async-loading'
|
|
||||||
import { distDir } from './dirs'
|
|
||||||
import { isDirectory, readDirRecursively } from './vite/utils/fs'
|
|
||||||
|
|
||||||
export async function setupNitroBridge () {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
// Ensure we're not just building with 'static' target
|
|
||||||
if (!nuxt.options.dev && nuxt.options.target === 'static' && !nuxt.options._prepare && !(nuxt.options as any)._export && !nuxt.options._legacyGenerate) {
|
|
||||||
throw new Error('[nitro] Please use `nuxt generate` for static target')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle legacy property name `assetsPath`
|
|
||||||
nuxt.options.app.buildAssetsDir = nuxt.options.app.buildAssetsDir || nuxt.options.app.assetsPath
|
|
||||||
nuxt.options.app.assetsPath = nuxt.options.app.buildAssetsDir
|
|
||||||
nuxt.options.app.baseURL = nuxt.options.app.baseURL || (nuxt.options.app as any).basePath
|
|
||||||
nuxt.options.app.cdnURL = nuxt.options.app.cdnURL || ''
|
|
||||||
|
|
||||||
// Extract publicConfig and app
|
|
||||||
const publicConfig = nuxt.options.publicRuntimeConfig
|
|
||||||
const appConfig = { ...publicConfig._app, ...publicConfig.app }
|
|
||||||
delete publicConfig.app
|
|
||||||
delete publicConfig._app
|
|
||||||
|
|
||||||
// Merge with new `runtimeConfig` format
|
|
||||||
nuxt.options.runtimeConfig = defu(nuxt.options.runtimeConfig, {
|
|
||||||
...publicConfig,
|
|
||||||
...nuxt.options.privateRuntimeConfig,
|
|
||||||
public: publicConfig,
|
|
||||||
app: appConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
// Disable loading-screen
|
|
||||||
// @ts-ignore
|
|
||||||
nuxt.options.build.loadingScreen = false
|
|
||||||
// @ts-ignore
|
|
||||||
nuxt.options.build.indicator = false
|
|
||||||
|
|
||||||
if (nuxt.options.build.analyze === true) {
|
|
||||||
const { rootDir } = nuxt.options
|
|
||||||
nuxt.options.build.analyze = {
|
|
||||||
template: 'treemap',
|
|
||||||
projectRoot: rootDir,
|
|
||||||
filename: join(rootDir, '.nuxt/stats', '{name}.html')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve Handlers
|
|
||||||
const { handlers, devHandlers } = await resolveHandlers(nuxt)
|
|
||||||
|
|
||||||
// Resolve config
|
|
||||||
const _nitroConfig = (nuxt.options as any).nitro || {} as NitroConfig
|
|
||||||
const nitroConfig: NitroConfig = defu(_nitroConfig, <NitroConfig>{
|
|
||||||
rootDir: resolve(nuxt.options.rootDir),
|
|
||||||
srcDir: resolve(nuxt.options.srcDir, 'server'),
|
|
||||||
dev: nuxt.options.dev,
|
|
||||||
preset: nuxt.options.dev ? 'nitro-dev' : undefined,
|
|
||||||
buildDir: resolve(nuxt.options.buildDir),
|
|
||||||
scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')),
|
|
||||||
renderer: resolve(distDir, 'runtime/nitro/renderer'),
|
|
||||||
errorHandler: resolve(distDir, 'runtime/nitro/error'),
|
|
||||||
nodeModulesDirs: nuxt.options.modulesDir,
|
|
||||||
handlers,
|
|
||||||
devHandlers: [],
|
|
||||||
runtimeConfig: {
|
|
||||||
...nuxt.options.runtimeConfig,
|
|
||||||
nitro: {
|
|
||||||
envPrefix: 'NUXT_',
|
|
||||||
...nuxt.options.runtimeConfig.nitro
|
|
||||||
}
|
|
||||||
},
|
|
||||||
typescript: {
|
|
||||||
generateTsConfig: false
|
|
||||||
},
|
|
||||||
publicAssets: [
|
|
||||||
{
|
|
||||||
baseURL: nuxt.options.app.buildAssetsDir,
|
|
||||||
dir: resolve(nuxt.options.buildDir, 'dist/client')
|
|
||||||
},
|
|
||||||
...nuxt.options._layers
|
|
||||||
.map(layer => join(layer.config.srcDir, 'public'))
|
|
||||||
.filter(dir => existsSync(dir))
|
|
||||||
.map(dir => ({ dir }))
|
|
||||||
],
|
|
||||||
prerender: {
|
|
||||||
crawlLinks: nuxt.options.generate.crawler,
|
|
||||||
routes: nuxt.options.generate.routes
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
inline: [
|
|
||||||
...(nuxt.options.dev ? [] : ['vue', '@vue/', '@nuxt/', nuxt.options.buildDir]),
|
|
||||||
'@nuxt/bridge/dist',
|
|
||||||
'@nuxt/bridge-edge/dist'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
alias: {
|
|
||||||
// Vue 2 mocks
|
|
||||||
encoding: 'unenv/runtime/mock/proxy',
|
|
||||||
he: 'unenv/runtime/mock/proxy',
|
|
||||||
resolve: 'unenv/runtime/mock/proxy',
|
|
||||||
'source-map': 'unenv/runtime/mock/proxy',
|
|
||||||
'lodash.template': 'unenv/runtime/mock/proxy',
|
|
||||||
'serialize-javascript': 'unenv/runtime/mock/proxy',
|
|
||||||
|
|
||||||
// Renderer
|
|
||||||
'#vue-renderer': resolve(distDir, 'runtime/nitro/vue2'),
|
|
||||||
'#vue2-server-renderer': 'vue-server-renderer/' + (nuxt.options.dev ? 'build.dev.js' : 'build.prod.js'),
|
|
||||||
|
|
||||||
// Paths
|
|
||||||
'#paths': resolve(distDir, 'runtime/nitro/paths'),
|
|
||||||
|
|
||||||
// Nuxt aliases
|
|
||||||
...nuxt.options.alias
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Let nitro handle #build for windows path normalization
|
|
||||||
delete nitroConfig.alias['#build']
|
|
||||||
|
|
||||||
// Extend nitro config with hook
|
|
||||||
await nuxt.callHook('nitro:config', nitroConfig)
|
|
||||||
|
|
||||||
// Initiate nitro
|
|
||||||
const nitro = await createNitro(nitroConfig)
|
|
||||||
|
|
||||||
// Expose nitro to modules
|
|
||||||
await nuxt.callHook('nitro:init', nitro)
|
|
||||||
|
|
||||||
// Shared vfs storage
|
|
||||||
nitro.vfs = nuxt.vfs = nitro.vfs || nuxt.vfs || {}
|
|
||||||
|
|
||||||
// Connect hooks
|
|
||||||
nuxt.hook('close', () => nitro.hooks.callHook('close'))
|
|
||||||
|
|
||||||
async function updateViteBase () {
|
|
||||||
const clientDist = resolve(nuxt.options.buildDir, 'dist/client')
|
|
||||||
|
|
||||||
// Remove public files that have been duplicated into buildAssetsDir
|
|
||||||
// TODO: Add option to configure this behaviour in vite
|
|
||||||
const publicDir = join(nuxt.options.srcDir, nuxt.options.dir.static)
|
|
||||||
let publicFiles: string[] = []
|
|
||||||
if (await isDirectory(publicDir)) {
|
|
||||||
publicFiles = readDirRecursively(publicDir).map(r => r.replace(publicDir, ''))
|
|
||||||
for (const file of publicFiles) {
|
|
||||||
try {
|
|
||||||
fsExtra.rmSync(join(clientDist, file))
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy doubly-nested /_nuxt/_nuxt files into buildAssetsDir
|
|
||||||
// TODO: Workaround vite issue
|
|
||||||
if (await isDirectory(clientDist)) {
|
|
||||||
const nestedAssetsPath = withoutTrailingSlash(join(clientDist, nuxt.options.app.buildAssetsDir))
|
|
||||||
|
|
||||||
if (await isDirectory(nestedAssetsPath)) {
|
|
||||||
await fsExtra.copy(nestedAssetsPath, clientDist, { recursive: true })
|
|
||||||
await fsExtra.remove(nestedAssetsPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nuxt.hook('generate:before', updateViteBase)
|
|
||||||
|
|
||||||
// .ts is supported for serverMiddleware
|
|
||||||
nuxt.options.extensions.push('ts')
|
|
||||||
|
|
||||||
// Disable server sourceMap, esbuild will generate for it.
|
|
||||||
nuxt.hook('webpack:config', (webpackConfigs) => {
|
|
||||||
const serverConfig = webpackConfigs.find(config => config.name === 'server')
|
|
||||||
if (serverConfig) {
|
|
||||||
serverConfig.devtool = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set up webpack plugin for node async loading
|
|
||||||
nuxt.hook('webpack:config', (webpackConfigs) => {
|
|
||||||
const serverConfig = webpackConfigs.find(config => config.name === 'server')
|
|
||||||
if (serverConfig) {
|
|
||||||
serverConfig.plugins = serverConfig.plugins || []
|
|
||||||
serverConfig.plugins.push(new AsyncLoadingPlugin({
|
|
||||||
modulesDir: nuxt.options.modulesDir
|
|
||||||
}) as any)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Nitro client plugin
|
|
||||||
addPluginTemplate({
|
|
||||||
filename: 'nitro-bridge.client.mjs',
|
|
||||||
src: resolve(distDir, 'runtime/nitro-bridge.client.mjs')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Nitro server plugin (for vue-meta)
|
|
||||||
addPluginTemplate({
|
|
||||||
filename: 'nitro-bridge.server.mjs',
|
|
||||||
src: resolve(distDir, 'runtime/nitro-bridge.server.mjs')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Fix module resolution
|
|
||||||
nuxt.hook('webpack:config', (configs) => {
|
|
||||||
for (const config of configs) {
|
|
||||||
// We use only object form of alias in base config
|
|
||||||
if (Array.isArray(config.resolve.alias)) { return }
|
|
||||||
config.resolve.alias.ufo = 'ufo/dist/index.mjs'
|
|
||||||
config.resolve.alias.ohmyfetch = 'ohmyfetch/dist/index.mjs'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generate mjs resources
|
|
||||||
nuxt.hook('build:compiled', async ({ name }) => {
|
|
||||||
if (nuxt.options._prepare) { return }
|
|
||||||
if (name === 'server') {
|
|
||||||
const jsServerEntry = resolve(nuxt.options.buildDir, 'dist/server/server.js')
|
|
||||||
await fsp.writeFile(jsServerEntry.replace(/.js$/, '.cjs'), 'module.exports = require("./server.js")', 'utf8')
|
|
||||||
await fsp.writeFile(jsServerEntry.replace(/.js$/, '.mjs'), 'export { default } from "./server.cjs"', 'utf8')
|
|
||||||
} else if (name === 'client') {
|
|
||||||
const manifest = await fsp.readFile(resolve(nuxt.options.buildDir, 'dist/server/client.manifest.json'), 'utf8')
|
|
||||||
await fsp.writeFile(resolve(nuxt.options.buildDir, 'dist/server/client.manifest.mjs'), 'export default ' + manifest, 'utf8')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Setup handlers
|
|
||||||
const devMidlewareHandler = dynamicEventHandler()
|
|
||||||
nitro.options.devHandlers.unshift({ handler: devMidlewareHandler })
|
|
||||||
nitro.options.devHandlers.push(...devHandlers)
|
|
||||||
nitro.options.handlers.unshift({
|
|
||||||
route: '/__nuxt_error',
|
|
||||||
lazy: true,
|
|
||||||
handler: resolve(distDir, 'runtime/nitro/renderer')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create dev server
|
|
||||||
if (nuxt.server) {
|
|
||||||
nuxt.server.__closed = true
|
|
||||||
nuxt.server = createNuxt2DevServer(nitro)
|
|
||||||
nuxt.hook('build:resources', () => {
|
|
||||||
nuxt.server.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add typed route responses
|
|
||||||
nuxt.hook('prepare:types', (opts) => {
|
|
||||||
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/nitro.d.ts') })
|
|
||||||
})
|
|
||||||
|
|
||||||
// nuxt prepare
|
|
||||||
nuxt.hook('build:done', async () => {
|
|
||||||
await writeTypes(nitro)
|
|
||||||
})
|
|
||||||
|
|
||||||
// nuxt build/dev
|
|
||||||
// @ts-ignore
|
|
||||||
nuxt.options.build._minifyServer = false
|
|
||||||
nuxt.options.build.standalone = false
|
|
||||||
|
|
||||||
const waitUntilCompile = new Promise<void>(resolve => nitro.hooks.hook('nitro:compiled', () => resolve()))
|
|
||||||
nuxt.hook('build:done', async () => {
|
|
||||||
if (nuxt.options._prepare) { return }
|
|
||||||
await writeDocumentTemplate(nuxt)
|
|
||||||
if (nuxt.options.dev) {
|
|
||||||
await build(nitro)
|
|
||||||
await waitUntilCompile
|
|
||||||
// nitro.hooks.callHook('nitro:dev:reload')
|
|
||||||
} else {
|
|
||||||
await prepare(nitro)
|
|
||||||
await copyPublicAssets(nitro)
|
|
||||||
if (nuxt.options._generate || nuxt.options.target === 'static') {
|
|
||||||
await prerender(nitro)
|
|
||||||
}
|
|
||||||
await build(nitro)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// nuxt dev
|
|
||||||
if (nuxt.options.dev) {
|
|
||||||
nuxt.hook('build:compile', ({ compiler }) => {
|
|
||||||
compiler.outputFileSystem = { ...fsExtra, join } as any
|
|
||||||
})
|
|
||||||
nuxt.hook('server:devMiddleware', (m) => { devMidlewareHandler.set(toEventHandler(m)) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// nuxt generate
|
|
||||||
nuxt.options.generate.dir = nitro.options.output.publicDir
|
|
||||||
nuxt.options.generate.manifest = false
|
|
||||||
nuxt.hook('generate:cache:ignore', (ignore: string[]) => {
|
|
||||||
ignore.push(nitro.options.output.dir)
|
|
||||||
ignore.push(nitro.options.output.serverDir)
|
|
||||||
if (nitro.options.output.publicDir) {
|
|
||||||
ignore.push(nitro.options.output.publicDir)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
nuxt.hook('generate:before', async () => {
|
|
||||||
console.log('generate:before')
|
|
||||||
await prepare(nitro)
|
|
||||||
})
|
|
||||||
nuxt.hook('generate:extendRoutes', async () => {
|
|
||||||
console.log('generate:extendRoutes')
|
|
||||||
await build(nitro)
|
|
||||||
await nuxt.server.reload()
|
|
||||||
})
|
|
||||||
nuxt.hook('generate:done', async () => {
|
|
||||||
console.log('generate:done')
|
|
||||||
await nuxt.server.close()
|
|
||||||
await build(nitro)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNuxt2DevServer (nitro: Nitro) {
|
|
||||||
const server = createDevServer(nitro)
|
|
||||||
|
|
||||||
const listeners = []
|
|
||||||
async function listen (port) {
|
|
||||||
const listener = await server.listen(port, {
|
|
||||||
showURL: false,
|
|
||||||
isProd: true
|
|
||||||
})
|
|
||||||
listeners.push(listener)
|
|
||||||
return listener
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderRoute (route = '/', renderContext = {}) {
|
|
||||||
const [listener] = listeners
|
|
||||||
if (!listener) {
|
|
||||||
throw new Error('There is no server listener to call `server.renderRoute()`')
|
|
||||||
}
|
|
||||||
const res = await fetch(joinURL(listener.url, route), {
|
|
||||||
headers: { 'nuxt-render-context': stringifyQuery(renderContext) }
|
|
||||||
})
|
|
||||||
|
|
||||||
const html = await res.text()
|
|
||||||
|
|
||||||
if (!res.ok) { return { html, error: res.statusText } }
|
|
||||||
|
|
||||||
return { html }
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...server,
|
|
||||||
listeners,
|
|
||||||
renderRoute,
|
|
||||||
listen,
|
|
||||||
serverMiddlewarePaths () { return [] },
|
|
||||||
ready () { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveHandlers (nuxt: Nuxt) {
|
|
||||||
const handlers: NitroEventHandler[] = []
|
|
||||||
const devHandlers: NitroDevEventHandler[] = []
|
|
||||||
|
|
||||||
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,
|
|
||||||
handler: await resolvePath(handler)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
handlers,
|
|
||||||
devHandlers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeDocumentTemplate (nuxt: Nuxt) {
|
|
||||||
// Compile html template
|
|
||||||
const src = nuxt.options.appTemplatePath || resolve(nuxt.options.buildDir, 'views/app.template.html')
|
|
||||||
const dst = src.replace(/.html$/, '.mjs').replace('app.template.mjs', 'document.template.mjs')
|
|
||||||
const contents = nuxt.vfs[src] || await fsp.readFile(src, 'utf-8').catch(() => '')
|
|
||||||
if (contents) {
|
|
||||||
const compiled = 'export default ' +
|
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
|
||||||
`(params) => \`${contents.replace(/{{ (\w+) }}/g, '${params.$1}')}\``
|
|
||||||
await fsp.mkdir(dirname(dst), { recursive: true })
|
|
||||||
await fsp.writeFile(dst, compiled, 'utf8')
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import { promisify } from 'util'
|
|
||||||
import defu from 'defu'
|
|
||||||
import enhancedResolve from 'enhanced-resolve'
|
|
||||||
import { ResolveOptions } from 'webpack/types'
|
|
||||||
import { extendWebpackConfig, useNuxt } from '@nuxt/kit'
|
|
||||||
|
|
||||||
type UserResolveOptions = Parameters<typeof enhancedResolve.ResolverFactory['createResolver']>[0]
|
|
||||||
type ResolverOptions = Omit<UserResolveOptions, 'fileSystem'> & { fileSystem?: enhancedResolve.CachedInputFileSystem }
|
|
||||||
|
|
||||||
const DEFAULTS: UserResolveOptions = {
|
|
||||||
fileSystem: new enhancedResolve.CachedInputFileSystem(fs, 4000),
|
|
||||||
extensions: ['.ts', '.tsx', '.mjs', '.cjs', '.js', '.jsx', '.json', '.vue']
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstracted resolver factory which can be used in rollup, webpack, etc.
|
|
||||||
const createResolver = (resolveOptions: ResolverOptions) => {
|
|
||||||
const options = defu(resolveOptions, DEFAULTS) as UserResolveOptions
|
|
||||||
const resolver = enhancedResolve.ResolverFactory.createResolver(options)
|
|
||||||
|
|
||||||
const root = options.roots?.[0] || '.'
|
|
||||||
|
|
||||||
const promisifiedResolve = promisify(resolver.resolve.bind(resolver)) as (context: object, path: string, request: string, resolveContext: enhancedResolve.ResolveContext) => Promise<string | false>
|
|
||||||
|
|
||||||
const resolve = (id: string, importer?: string) => promisifiedResolve({}, importer || root, id, {})
|
|
||||||
|
|
||||||
return { resolve, resolver }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Webpack plugin to add first-level support for subpath exports, etc.
|
|
||||||
class EnhancedResolverPlugin {
|
|
||||||
resolver: ReturnType<typeof createResolver>
|
|
||||||
|
|
||||||
constructor (options: ResolverOptions) {
|
|
||||||
this.resolver = createResolver(options)
|
|
||||||
}
|
|
||||||
|
|
||||||
apply (defaultResolver: any) {
|
|
||||||
const enhancedResolver = this.resolver
|
|
||||||
|
|
||||||
defaultResolver.getHook('resolve').tapPromise('EnhancedResolverPlugin', async (request) => {
|
|
||||||
const id = request.request
|
|
||||||
// Fall back to default webpack4 resolver if not a node_modules import
|
|
||||||
if (!id || !defaultResolver.isModule(id)) { return }
|
|
||||||
|
|
||||||
// Fall back to webpack4 resolver if resolving babel helpers
|
|
||||||
// https://github.com/nuxt/nuxt.js/blob/714249740690569eedf74aa7bca7ed31c01953d4/packages/babel-preset-app/src/index.js#L169
|
|
||||||
if (id.includes('@babel/')) { return }
|
|
||||||
|
|
||||||
const importer = request.context?.issuer
|
|
||||||
try {
|
|
||||||
const result = await enhancedResolver.resolve(id, importer)
|
|
||||||
// Fall back to default webpack4 resolver if we can't resolve id
|
|
||||||
if (!result) { return }
|
|
||||||
request.path = result
|
|
||||||
return request
|
|
||||||
} catch {
|
|
||||||
// Fall back to default webpack4 resolver in the event of error
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupBetterResolve () {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
extendWebpackConfig((config) => {
|
|
||||||
const isServer = config.name === 'server'
|
|
||||||
|
|
||||||
config.resolve = config.resolve || {}
|
|
||||||
config.resolve.plugins = config.resolve.plugins || []
|
|
||||||
|
|
||||||
config.resolve.plugins.push(new EnhancedResolverPlugin({
|
|
||||||
conditionNames: ['import', ...isServer ? ['node'] : []],
|
|
||||||
mainFields: ['module', ...isServer ? [] : ['browser'], 'main'],
|
|
||||||
alias: config.resolve.alias,
|
|
||||||
modules: config.resolve.modules,
|
|
||||||
plugins: config.resolve.plugins as Array<Exclude<ResolveOptions['plugins'][number], string>>,
|
|
||||||
roots: config.resolve.roots || [nuxt.options.rootDir]
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import { createHooks } from 'hookable'
|
|
||||||
import { callWithNuxt, setNuxtAppInstance } from '#app'
|
|
||||||
|
|
||||||
// Reshape payload to match key `useLazyAsyncData` expects
|
|
||||||
function proxiedState (state) {
|
|
||||||
state._asyncData = state._asyncData || {}
|
|
||||||
state._errors = state._errors || {}
|
|
||||||
return new Proxy(state, {
|
|
||||||
get (target, prop) {
|
|
||||||
if (prop === 'data') {
|
|
||||||
return target._asyncData
|
|
||||||
}
|
|
||||||
if (prop === '_data') {
|
|
||||||
return target.state
|
|
||||||
}
|
|
||||||
return Reflect.get(target, prop)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const runOnceWith = (obj, fn) => {
|
|
||||||
if (!obj || !['function', 'object'].includes(typeof obj)) {
|
|
||||||
return fn()
|
|
||||||
}
|
|
||||||
if (obj.__nuxt_installed) { return }
|
|
||||||
obj.__nuxt_installed = true
|
|
||||||
return fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async (ctx, inject) => {
|
|
||||||
const nuxtApp = {
|
|
||||||
vueApp: {
|
|
||||||
component: (id, definition) => runOnceWith(definition, () => Vue.component(id, definition)),
|
|
||||||
config: {
|
|
||||||
globalProperties: {}
|
|
||||||
},
|
|
||||||
directive: (id, definition) => runOnceWith(definition, () => Vue.directive(id, definition)),
|
|
||||||
mixin: mixin => runOnceWith(mixin, () => Vue.mixin(mixin)),
|
|
||||||
mount: () => { },
|
|
||||||
provide: inject,
|
|
||||||
unmount: () => { },
|
|
||||||
use (vuePlugin) {
|
|
||||||
runOnceWith(vuePlugin, () => vuePlugin.install(this))
|
|
||||||
},
|
|
||||||
version: Vue.version
|
|
||||||
},
|
|
||||||
provide: inject,
|
|
||||||
globalName: 'nuxt',
|
|
||||||
payload: proxiedState(process.client ? ctx.nuxtState : ctx.ssrContext.nuxt),
|
|
||||||
_asyncDataPromises: [],
|
|
||||||
isHydrating: true,
|
|
||||||
nuxt2Context: ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
nuxtApp.hooks = createHooks()
|
|
||||||
nuxtApp.hook = nuxtApp.hooks.hook
|
|
||||||
nuxtApp.callHook = nuxtApp.hooks.callHook
|
|
||||||
|
|
||||||
const middleware = await import('#build/middleware').then(r => r.default)
|
|
||||||
nuxtApp._middleware = nuxtApp._middleware || {
|
|
||||||
global: [],
|
|
||||||
named: middleware
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.app.router.beforeEach(async (to, from, next) => {
|
|
||||||
nuxtApp._processingMiddleware = true
|
|
||||||
|
|
||||||
for (const middleware of nuxtApp._middleware.global) {
|
|
||||||
const result = await callWithNuxt(nuxtApp, middleware, [to, from])
|
|
||||||
if (result || result === false) { return next(result) }
|
|
||||||
}
|
|
||||||
|
|
||||||
next()
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.app.router.afterEach(() => {
|
|
||||||
delete nuxtApp._processingMiddleware
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!Array.isArray(ctx.app.created)) {
|
|
||||||
ctx.app.created = [ctx.app.created].filter(Boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(ctx.app.mounted)) {
|
|
||||||
ctx.app.mounted = [ctx.app.mounted].filter(Boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.server) {
|
|
||||||
nuxtApp.ssrContext = ctx.ssrContext
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.app.created.push(function () {
|
|
||||||
nuxtApp.vue2App = this
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.app.mounted.push(() => { nuxtApp.isHydrating = false })
|
|
||||||
|
|
||||||
const proxiedApp = new Proxy(nuxtApp, {
|
|
||||||
get (target, prop) {
|
|
||||||
if (prop[0] === '$') {
|
|
||||||
return target.nuxt2Context[prop] || target.vue2App?.[prop]
|
|
||||||
}
|
|
||||||
return Reflect.get(target, prop)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
setNuxtAppInstance(proxiedApp)
|
|
||||||
|
|
||||||
if (process.client) {
|
|
||||||
window.onNuxtReady(() => {
|
|
||||||
nuxtApp.hooks.callHook('app:mounted', nuxtApp.vueApp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
inject('_nuxtApp', proxiedApp)
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
import type { Hookable } from 'hookable'
|
|
||||||
// @ts-ignore
|
|
||||||
import type { Vue } from 'vue/types/vue'
|
|
||||||
import type { ComponentOptions } from 'vue'
|
|
||||||
import { defineComponent, getCurrentInstance } from './composables'
|
|
||||||
|
|
||||||
export const isVue2 = true
|
|
||||||
export const isVue3 = false
|
|
||||||
|
|
||||||
export const defineNuxtComponent = defineComponent
|
|
||||||
|
|
||||||
export interface VueAppCompat {
|
|
||||||
component: Vue['component'],
|
|
||||||
config: {
|
|
||||||
globalProperties: any
|
|
||||||
[key: string]: any
|
|
||||||
},
|
|
||||||
directive: Vue['directive'],
|
|
||||||
mixin: Vue['mixin'],
|
|
||||||
mount: Vue['mount'],
|
|
||||||
provide: (name: string, value: any) => void,
|
|
||||||
unmount: Vue['unmount'],
|
|
||||||
use: Vue['use']
|
|
||||||
version: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RuntimeNuxtHooks {
|
|
||||||
'vue:setup': () => void
|
|
||||||
'app:mounted': (app: VueAppCompat) => void | Promise<void>
|
|
||||||
'meta:register': (metaRenderers: any[]) => void | Promise<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NuxtAppCompat {
|
|
||||||
nuxt2Context: Vue
|
|
||||||
vue2App: ComponentOptions<Vue>
|
|
||||||
|
|
||||||
vueApp: VueAppCompat
|
|
||||||
|
|
||||||
globalName: string
|
|
||||||
|
|
||||||
hooks: Hookable<RuntimeNuxtHooks>
|
|
||||||
hook: NuxtAppCompat['hooks']['hook']
|
|
||||||
callHook: NuxtAppCompat['hooks']['callHook']
|
|
||||||
|
|
||||||
[key: string]: any
|
|
||||||
|
|
||||||
ssrContext?: Record<string, any>
|
|
||||||
payload: {
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
provide: (name: string, value: any) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Context {
|
|
||||||
$_nuxtApp: NuxtAppCompat
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentNuxtAppInstance: NuxtAppCompat | null
|
|
||||||
|
|
||||||
export const setNuxtAppInstance = (nuxt: NuxtAppCompat | null) => {
|
|
||||||
currentNuxtAppInstance = nuxt
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that the setup function passed in has access to the Nuxt instance via `useNuxt`.
|
|
||||||
*
|
|
||||||
* @param nuxt A Nuxt instance
|
|
||||||
* @param setup The function to call
|
|
||||||
*/
|
|
||||||
export function callWithNuxt<T extends (...args: any[]) => any> (nuxt: NuxtAppCompat, setup: T, args?: Parameters<T>) {
|
|
||||||
setNuxtAppInstance(nuxt)
|
|
||||||
const p: ReturnType<T> = args ? setup(...args as Parameters<T>) : setup()
|
|
||||||
if (process.server) {
|
|
||||||
// Unset nuxt instance to prevent context-sharing in server-side
|
|
||||||
setNuxtAppInstance(null)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Plugin {
|
|
||||||
(nuxt: NuxtAppCompat): Promise<void> | Promise<{ provide?: Record<string, any> }> | void | { provide?: Record<string, any> }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function defineNuxtPlugin (plugin: Plugin): (ctx: Context, inject: (id: string, value: any) => void) => void {
|
|
||||||
return async (ctx, inject) => {
|
|
||||||
const result = await callWithNuxt(ctx.$_nuxtApp, plugin, [ctx.$_nuxtApp])
|
|
||||||
if (result && result.provide) {
|
|
||||||
for (const key in result.provide) {
|
|
||||||
inject(key, result.provide[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useNuxtApp = (): NuxtAppCompat => {
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
|
|
||||||
if (!vm) {
|
|
||||||
if (!currentNuxtAppInstance) {
|
|
||||||
throw new Error('nuxt app instance unavailable')
|
|
||||||
}
|
|
||||||
return currentNuxtAppInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm.proxy.$_nuxtApp
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/app/composables/asyncData.ts
|
|
@ -1,559 +0,0 @@
|
|||||||
import defu from 'defu'
|
|
||||||
import { computed, getCurrentInstance as getVM, isReactive, isRef, onBeforeMount, onServerPrefetch, reactive, ref, set, shallowRef, toRaw, toRefs, watch } from '@vue/composition-api'
|
|
||||||
import { useNuxtApp } from './app'
|
|
||||||
import { useRouter as _useRouter, useState } from './composables'
|
|
||||||
|
|
||||||
// Vue composition API export
|
|
||||||
export {
|
|
||||||
computed,
|
|
||||||
createApp,
|
|
||||||
createRef,
|
|
||||||
customRef,
|
|
||||||
defineAsyncComponent,
|
|
||||||
del,
|
|
||||||
effectScope,
|
|
||||||
getCurrentInstance,
|
|
||||||
getCurrentScope,
|
|
||||||
h,
|
|
||||||
inject,
|
|
||||||
isRaw,
|
|
||||||
isReactive,
|
|
||||||
isReadonly,
|
|
||||||
isRef,
|
|
||||||
markRaw,
|
|
||||||
nextTick,
|
|
||||||
onActivated,
|
|
||||||
onBeforeMount,
|
|
||||||
onBeforeUnmount,
|
|
||||||
onBeforeUpdate,
|
|
||||||
onDeactivated,
|
|
||||||
onErrorCaptured,
|
|
||||||
onMounted,
|
|
||||||
onScopeDispose,
|
|
||||||
onServerPrefetch,
|
|
||||||
onUnmounted,
|
|
||||||
onUpdated,
|
|
||||||
provide,
|
|
||||||
proxyRefs,
|
|
||||||
reactive,
|
|
||||||
readonly,
|
|
||||||
set,
|
|
||||||
shallowReactive,
|
|
||||||
shallowReadonly,
|
|
||||||
shallowRef,
|
|
||||||
toRaw,
|
|
||||||
toRef,
|
|
||||||
toRefs,
|
|
||||||
triggerRef,
|
|
||||||
unref,
|
|
||||||
useAttrs,
|
|
||||||
useCssModule,
|
|
||||||
useCSSModule,
|
|
||||||
useSlots,
|
|
||||||
version,
|
|
||||||
warn,
|
|
||||||
watch,
|
|
||||||
watchEffect,
|
|
||||||
watchPostEffect,
|
|
||||||
watchSyncEffect
|
|
||||||
} from '@vue/composition-api'
|
|
||||||
|
|
||||||
export { ref }
|
|
||||||
|
|
||||||
// Common deprecation utils
|
|
||||||
// TODO: Add migration guide docs to @nuxtjs/composition-api
|
|
||||||
const checkDocsMsg = 'Please see https://v3.nuxtjs.org/bridge/bridge-composition-api for more information.'
|
|
||||||
const msgPrefix = '[bridge] [legacy capi]'
|
|
||||||
const unsupported = message => () => { throw new Error(`${msgPrefix} ${message} ${checkDocsMsg}`) }
|
|
||||||
const _warned = {}
|
|
||||||
const warnOnce = (id, message) => {
|
|
||||||
if (!_warned[id]) {
|
|
||||||
console.warn(msgPrefix, message, checkDocsMsg)
|
|
||||||
_warned[id] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn in case of having any imports from `@nuxtjs/composition-api`
|
|
||||||
warnOnce('import', '`@nuxtjs/composition-api` is deprecated.')
|
|
||||||
|
|
||||||
// Stub functions that provided type support
|
|
||||||
export const defineNuxtMiddleware = unsupported('You are using `defineNuxtMiddleware`, which is not supported.')
|
|
||||||
export const defineNuxtPlugin = unsupported('You are using `defineNuxtPlugin`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
// Internal exports
|
|
||||||
export const setMetaPlugin = unsupported('`setMetaPlugin` is an internal function that is no longer used.')
|
|
||||||
export const setSSRContext = unsupported('`setSSRContext` is an internal function that is no longer used.')
|
|
||||||
export const globalPlugin = unsupported('`globalPlugin` is an internal function that is no longer used.')
|
|
||||||
|
|
||||||
// Deprecated functions
|
|
||||||
export const withContext = unsupported('`withContext` is a deprecated method that is no longer provided, but which has a Nuxt 3-compatible replacement.')
|
|
||||||
export const useStatic = unsupported('`useStatic` is a deprecated method that is no longer provided.')
|
|
||||||
export const reqRef = unsupported('`reqRef` is a deprecated method that is no longer provided, but which has a Nuxt 3-compatible replacement.')
|
|
||||||
export const reqSsrRef = unsupported('`reqSsrRef` is no longer provided, but has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
// ssrRef helpers
|
|
||||||
const sanitise = val => (val && JSON.parse(JSON.stringify(val))) || val
|
|
||||||
const getValue = val => val instanceof Function ? val() : val
|
|
||||||
|
|
||||||
export const ssrRef = (value, key) => {
|
|
||||||
const vm = getVM()
|
|
||||||
if (!vm) { throw new Error('ssrRef no longer supports global/ambient context and must be called within a setup() function') }
|
|
||||||
|
|
||||||
warnOnce('ssrRef', '`ssrRef` is deprecated and has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
return useState(key, value instanceof Function ? value : () => value)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const shallowSsrRef = (value, key) => {
|
|
||||||
warnOnce('shallowSsrRef', '`shallowSsrRef` is deprecated and has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
const ref = ssrRef(value, key)
|
|
||||||
|
|
||||||
if (process.client) {
|
|
||||||
return shallowRef(ref.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ssrPromise = (value, key) => {
|
|
||||||
warnOnce('ssrPromise', 'ssrPromise is deprecated.')
|
|
||||||
|
|
||||||
const ssrRefs = useSSRRefs()
|
|
||||||
const promise = Promise.resolve(isHMR() ? getValue(value) : ssrRefs[key] ?? getValue(value))
|
|
||||||
|
|
||||||
onServerPrefetch(async () => { ssrRefs[key] = sanitise(await promise) })
|
|
||||||
return promise
|
|
||||||
}
|
|
||||||
|
|
||||||
// Composition API functions
|
|
||||||
export const onGlobalSetup = (fn) => {
|
|
||||||
warnOnce('onGlobalSetup', '`onGlobalSetup` is deprecated and has a Nuxt 3-compatible replacement.')
|
|
||||||
useNuxtApp().hook('vue:setup', fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAsync = (cb, key) => {
|
|
||||||
warnOnce('useAsync', 'You are using `useAsync`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
const _ref = isRef(key) ? key : ssrRef(null, key)
|
|
||||||
|
|
||||||
if (!_ref.value || isHMR()) {
|
|
||||||
const p = Promise.resolve(cb()).then(res => (_ref.value = res))
|
|
||||||
onServerPrefetch(() => p)
|
|
||||||
}
|
|
||||||
|
|
||||||
return _ref
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useContext = () => {
|
|
||||||
warnOnce('useContext', 'You are using `useContext`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const nuxt = useNuxtApp()
|
|
||||||
|
|
||||||
return {
|
|
||||||
...nuxt.nuxt2Context,
|
|
||||||
route: computed(() => route),
|
|
||||||
query: computed(() => route.value.query),
|
|
||||||
from: computed(() => nuxt.nuxt2Context.from),
|
|
||||||
params: computed(() => route.value.params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEmptyMeta () {
|
|
||||||
return {
|
|
||||||
titleTemplate: null,
|
|
||||||
|
|
||||||
__dangerouslyDisableSanitizers: [],
|
|
||||||
__dangerouslyDisableSanitizersByTagID: {},
|
|
||||||
|
|
||||||
title: undefined,
|
|
||||||
htmlAttrs: {},
|
|
||||||
headAttrs: {},
|
|
||||||
bodyAttrs: {},
|
|
||||||
|
|
||||||
base: undefined,
|
|
||||||
|
|
||||||
meta: [],
|
|
||||||
link: [],
|
|
||||||
style: [],
|
|
||||||
script: [],
|
|
||||||
noscript: [],
|
|
||||||
|
|
||||||
changed: undefined,
|
|
||||||
afterNavigation: undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getHeadOptions = (options) => {
|
|
||||||
const head = function () {
|
|
||||||
const optionHead =
|
|
||||||
options.head instanceof Function ? options.head.call(this) : options.head
|
|
||||||
|
|
||||||
if (!this._computedHead) { return optionHead }
|
|
||||||
|
|
||||||
const computedHead = this._computedHead.map((h) => {
|
|
||||||
if (isReactive(h)) { return toRaw(h) }
|
|
||||||
if (isRef(h)) { return h.value }
|
|
||||||
return h
|
|
||||||
})
|
|
||||||
return defu({}, ...computedHead.reverse(), optionHead)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { head }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defineComponent = (options) => {
|
|
||||||
if (!('head' in options)) { return options }
|
|
||||||
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
...getHeadOptions(options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useMeta = (init) => {
|
|
||||||
warnOnce('useMeta', 'You are using `useMeta`, which has a replacement provided by Nuxt Bridge.')
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
const refreshMeta = () => vm.$meta().refresh()
|
|
||||||
|
|
||||||
if (!vm._computedHead) {
|
|
||||||
const metaRefs = reactive(createEmptyMeta())
|
|
||||||
vm._computedHead = [metaRefs]
|
|
||||||
vm._metaRefs = toRefs(metaRefs)
|
|
||||||
|
|
||||||
if (process.client) {
|
|
||||||
watch(Object.values(vm._metaRefs), refreshMeta, { immediate: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (init) {
|
|
||||||
const initRef = init instanceof Function ? computed(init) : ref(init)
|
|
||||||
vm._computedHead.push(initRef)
|
|
||||||
|
|
||||||
if (process.client) {
|
|
||||||
watch(initRef, refreshMeta, { immediate: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm._metaRefs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapped properties
|
|
||||||
export const wrapProperty = (property, makeComputed = true) => () => {
|
|
||||||
warnOnce('wrapProperty', 'You are using `wrapProperty`, which is deprecated.')
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
return makeComputed ? computed(() => vm[property]) : vm[property]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useRouter = () => {
|
|
||||||
warnOnce('useRouter', 'You are using `useRouter`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
return _useRouter()
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useRoute = () => {
|
|
||||||
warnOnce('useRoute', 'You are using `useRoute`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
return computed(() => vm.$route)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useStore = () => {
|
|
||||||
warnOnce('useRoute', 'You are using `useStore`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
return getCurrentInstance().$store
|
|
||||||
}
|
|
||||||
|
|
||||||
// useFetch and helper functions
|
|
||||||
|
|
||||||
const fetches = new WeakMap()
|
|
||||||
const fetchPromises = new Map()
|
|
||||||
|
|
||||||
const mergeDataOnMount = (data) => {
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
if (!vm) { throw new Error('This must be called within a setup function.') }
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
// Merge data
|
|
||||||
for (const key in data) {
|
|
||||||
try {
|
|
||||||
// Assign missing properties
|
|
||||||
if (key in vm) {
|
|
||||||
// Skip functions (not stringifiable)
|
|
||||||
if (typeof vm[key] === 'function') { continue }
|
|
||||||
// Preserve reactive objects
|
|
||||||
if (isReactive(vm[key])) {
|
|
||||||
// Unset keys that do not exist in incoming data
|
|
||||||
for (const k in vm[key]) {
|
|
||||||
if (!(k in data[key])) {
|
|
||||||
delete vm[key][k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.assign(vm[key], data[key])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set(vm, key, data[key])
|
|
||||||
} catch (e) {
|
|
||||||
if (process.env.NODE_ENV === 'development')
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.warn(`Could not hydrate ${key}.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function createGetCounter (counterObject, defaultKey = '') {
|
|
||||||
return function getCounter (id = defaultKey) {
|
|
||||||
if (counterObject[id] === undefined) {
|
|
||||||
counterObject[id] = 0
|
|
||||||
}
|
|
||||||
return counterObject[id]++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setFetchState = (vm) => {
|
|
||||||
vm.$fetchState =
|
|
||||||
vm.$fetchState ||
|
|
||||||
reactive({
|
|
||||||
error: null,
|
|
||||||
pending: false,
|
|
||||||
timestamp: 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKey (vm) {
|
|
||||||
const nuxt = useNuxtApp()
|
|
||||||
const nuxtState = nuxt.payload
|
|
||||||
if (process.server && 'push' in vm.$ssrContext.nuxt.fetch) {
|
|
||||||
return undefined
|
|
||||||
} else if (process.client && '_payloadFetchIndex' in nuxtState) {
|
|
||||||
nuxtState._payloadFetchIndex = nuxtState._payloadFetchIndex || 0
|
|
||||||
return nuxtState._payloadFetchIndex++
|
|
||||||
}
|
|
||||||
const defaultKey = vm.$options._scopeId || vm.$options.name || ''
|
|
||||||
const getCounter = createGetCounter(
|
|
||||||
process.server
|
|
||||||
? vm.$ssrContext.fetchCounters
|
|
||||||
: nuxt.vue2App._fetchCounters,
|
|
||||||
defaultKey
|
|
||||||
)
|
|
||||||
|
|
||||||
if (typeof vm.$options.fetchKey === 'function') {
|
|
||||||
return vm.$options.fetchKey.call(vm, getCounter)
|
|
||||||
} else {
|
|
||||||
const key = typeof vm.$options.fetchKey === 'string' ? vm.$options.fetchKey : defaultKey
|
|
||||||
return key ? key + ':' + getCounter(key) : String(getCounter(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeError (err) {
|
|
||||||
let message
|
|
||||||
if (!(err.message || typeof err === 'string')) {
|
|
||||||
try {
|
|
||||||
message = JSON.stringify(err, null, 2)
|
|
||||||
} catch (e) {
|
|
||||||
message = `[${err.constructor.name}]`
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message = err.message || err
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...err,
|
|
||||||
message,
|
|
||||||
statusCode:
|
|
||||||
err.statusCode ||
|
|
||||||
err.status ||
|
|
||||||
(err.response && err.response.status) ||
|
|
||||||
500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadFullStatic = (vm) => {
|
|
||||||
vm._fetchKey = getKey(vm)
|
|
||||||
// Check if component has been fetched on server
|
|
||||||
const { fetchOnServer } = vm.$options
|
|
||||||
const fetchedOnServer =
|
|
||||||
typeof fetchOnServer === 'function'
|
|
||||||
? fetchOnServer.call(vm) !== false
|
|
||||||
: fetchOnServer !== false
|
|
||||||
|
|
||||||
if (!fetchedOnServer || vm.$nuxt?.isPreview || !vm.$nuxt?._pagePayload) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vm._hydrated = true
|
|
||||||
const data = vm.$nuxt._pagePayload.fetch[vm._fetchKey]
|
|
||||||
|
|
||||||
// If fetch error
|
|
||||||
if (data && data._error) {
|
|
||||||
vm.$fetchState.error = data._error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeDataOnMount(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function serverPrefetch (vm) {
|
|
||||||
if (!vm._fetchOnServer) { return }
|
|
||||||
|
|
||||||
// Call and await on $fetch
|
|
||||||
setFetchState(vm)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await callFetches.call(vm)
|
|
||||||
} catch (err) {
|
|
||||||
if (process.dev) {
|
|
||||||
console.error('Error in fetch():', err)
|
|
||||||
}
|
|
||||||
vm.$fetchState.error = normalizeError(err)
|
|
||||||
}
|
|
||||||
vm.$fetchState.pending = false
|
|
||||||
|
|
||||||
// Define an ssrKey for hydration
|
|
||||||
vm._fetchKey =
|
|
||||||
// Nuxt 2.15+ uses a different format - an object rather than an array
|
|
||||||
'push' in vm.$ssrContext.nuxt.fetch
|
|
||||||
? vm.$ssrContext.nuxt.fetch.length
|
|
||||||
: vm._fetchKey || vm.$ssrContext.fetchCounters['']++
|
|
||||||
|
|
||||||
// Add data-fetch-key on parent element of Component
|
|
||||||
if (!vm.$vnode.data) { vm.$vnode.data = {} }
|
|
||||||
const attrs = (vm.$vnode.data.attrs = vm.$vnode.data.attrs || {})
|
|
||||||
attrs['data-fetch-key'] = vm._fetchKey
|
|
||||||
|
|
||||||
const data = { ...vm._data }
|
|
||||||
Object.entries(vm.__composition_api_state__.rawBindings).forEach(
|
|
||||||
([key, val]) => {
|
|
||||||
if (val instanceof Function || val instanceof Promise) { return }
|
|
||||||
|
|
||||||
data[key] = isRef(val) ? val.value : val
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add to ssrContext for window.__NUXT__.fetch
|
|
||||||
const content = vm.$fetchState.error
|
|
||||||
? { _error: vm.$fetchState.error }
|
|
||||||
: JSON.parse(JSON.stringify(data))
|
|
||||||
if ('push' in vm.$ssrContext.nuxt.fetch) {
|
|
||||||
vm.$ssrContext.nuxt.fetch.push(content)
|
|
||||||
} else {
|
|
||||||
vm.$ssrContext.nuxt.fetch[vm._fetchKey] = content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function callFetches () {
|
|
||||||
const fetchesToCall = fetches.get(this)
|
|
||||||
if (!fetchesToCall) { return }
|
|
||||||
this.$nuxt.nbFetching++
|
|
||||||
|
|
||||||
this.$fetchState.pending = true
|
|
||||||
this.$fetchState.error = null
|
|
||||||
this._hydrated = false
|
|
||||||
|
|
||||||
let error = null
|
|
||||||
const startTime = Date.now()
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Promise.all(
|
|
||||||
fetchesToCall.map((fetch) => {
|
|
||||||
if (fetchPromises.has(fetch)) { return fetchPromises.get(fetch) }
|
|
||||||
const promise = Promise.resolve(fetch(this)).finally(() =>
|
|
||||||
fetchPromises.delete(fetch)
|
|
||||||
)
|
|
||||||
fetchPromises.set(fetch, promise)
|
|
||||||
return promise
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} catch (err) {
|
|
||||||
if (process.dev) {
|
|
||||||
console.error('Error in fetch():', err)
|
|
||||||
}
|
|
||||||
error = normalizeError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const delayLeft = (this._fetchDelay || 0) - (Date.now() - startTime)
|
|
||||||
if (delayLeft > 0) {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, delayLeft))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$fetchState.error = error
|
|
||||||
this.$fetchState.pending = false
|
|
||||||
this.$fetchState.timestamp = Date.now()
|
|
||||||
|
|
||||||
this.$nextTick(() => (this.$nuxt).nbFetching--)
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSsrHydration = vm => vm.$vnode?.elm?.dataset?.fetchKey
|
|
||||||
|
|
||||||
export const useFetch = (callback) => {
|
|
||||||
warnOnce('useFetch', 'You are using `useFetch`, which has a Nuxt 3-compatible replacement.')
|
|
||||||
const vm = getCurrentInstance()
|
|
||||||
const nuxt = useNuxtApp()
|
|
||||||
|
|
||||||
const nuxtState = nuxt.payload
|
|
||||||
|
|
||||||
const callbacks = fetches.get(vm) || []
|
|
||||||
fetches.set(vm, [...callbacks, callback])
|
|
||||||
|
|
||||||
if (typeof vm.$options.fetchOnServer === 'function') {
|
|
||||||
vm._fetchOnServer = vm.$options.fetchOnServer.call(vm) !== false
|
|
||||||
} else {
|
|
||||||
vm._fetchOnServer = vm.$options.fetchOnServer !== false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.server) {
|
|
||||||
vm._fetchKey = getKey(vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
setFetchState(vm)
|
|
||||||
|
|
||||||
onServerPrefetch(() => serverPrefetch(vm))
|
|
||||||
|
|
||||||
function result () {
|
|
||||||
return {
|
|
||||||
fetch: vm.$fetch,
|
|
||||||
fetchState: vm.$fetchState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm._fetchDelay =
|
|
||||||
typeof vm.$options.fetchDelay === 'number' ? vm.$options.fetchDelay : 0
|
|
||||||
|
|
||||||
vm.$fetch = callFetches.bind(vm)
|
|
||||||
|
|
||||||
onBeforeMount(() => !vm._hydrated && callFetches.call(vm))
|
|
||||||
|
|
||||||
if (process.server || !isSsrHydration(vm)) {
|
|
||||||
if (process.client && !process.dev && process.static) { loadFullStatic(vm) }
|
|
||||||
return result()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hydrate component
|
|
||||||
vm._hydrated = true
|
|
||||||
vm._fetchKey = vm.$vnode.elm?.dataset.fetchKey || getKey(vm)
|
|
||||||
const data = nuxtState.fetch[vm._fetchKey]
|
|
||||||
|
|
||||||
// If fetch error
|
|
||||||
if (data && data._error) {
|
|
||||||
vm.$fetchState.error = data._error
|
|
||||||
return result()
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeDataOnMount(data)
|
|
||||||
|
|
||||||
return result()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Private shared utils (across composables) --
|
|
||||||
|
|
||||||
function getCurrentInstance () {
|
|
||||||
const vm = getVM()
|
|
||||||
if (!vm) { throw new Error('This must be called within a setup function.') }
|
|
||||||
return vm.proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
const useSSRRefs = () => {
|
|
||||||
const { payload } = useNuxtApp()
|
|
||||||
payload.ssrRefs = payload.ssrRefs || {}
|
|
||||||
return payload.ssrRefs
|
|
||||||
}
|
|
||||||
|
|
||||||
const isHMR = () => process.env.NODE_ENV === 'development' && process.client && window.$nuxt?.context.isHMR
|
|
@ -1,20 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import VueCompositionAPI from '@vue/composition-api'
|
|
||||||
import { defineNuxtPlugin } from '#app'
|
|
||||||
|
|
||||||
Vue.use(VueCompositionAPI.default || VueCompositionAPI)
|
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
|
||||||
const _originalSetup = nuxtApp.nuxt2Context.app.setup
|
|
||||||
|
|
||||||
nuxtApp.nuxt2Context.app.setup = function (...args) {
|
|
||||||
const result = _originalSetup instanceof Function ? _originalSetup(...args) : {}
|
|
||||||
|
|
||||||
const hookResult = nuxtApp.hooks.callHookWith(hooks => hooks.map(hook => hook()), 'vue:setup')
|
|
||||||
if (process.dev && hookResult && hookResult.some(i => i && 'then' in i)) {
|
|
||||||
console.error('[nuxt] Error in `vue:setup`. Callbacks must be synchronous.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,244 +0,0 @@
|
|||||||
import { getCurrentInstance, onBeforeUnmount, isRef, watch, reactive, toRef, isReactive, Ref, set } from '@vue/composition-api'
|
|
||||||
import type { CombinedVueInstance } from 'vue/types/vue'
|
|
||||||
import type { MetaInfo } from 'vue-meta'
|
|
||||||
import type VueRouter from 'vue-router'
|
|
||||||
import type { Location, Route } from 'vue-router'
|
|
||||||
import type { RuntimeConfig } from '@nuxt/schema'
|
|
||||||
import { sendRedirect } from 'h3'
|
|
||||||
import defu from 'defu'
|
|
||||||
import { useNuxtApp } from './app'
|
|
||||||
|
|
||||||
export { useLazyAsyncData, refreshNuxtData } from './asyncData'
|
|
||||||
export { useLazyFetch } from './fetch'
|
|
||||||
export { useCookie } from './cookie'
|
|
||||||
export { useRequestHeaders } from './ssr'
|
|
||||||
|
|
||||||
export * from '@vue/composition-api'
|
|
||||||
|
|
||||||
const mock = () => () => { throw new Error('not implemented') }
|
|
||||||
|
|
||||||
export const useAsyncData = mock()
|
|
||||||
export const useFetch = mock()
|
|
||||||
export const useHydration = mock()
|
|
||||||
|
|
||||||
// Runtime config helper
|
|
||||||
export const useRuntimeConfig = () => {
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
if (!nuxtApp.$config) {
|
|
||||||
const runtimeConfig = reactive(nuxtApp.nuxt2Context.app.$config)
|
|
||||||
const compatibilityConfig = new Proxy(runtimeConfig, {
|
|
||||||
get (target, prop) {
|
|
||||||
if (prop === 'public') {
|
|
||||||
return target.public
|
|
||||||
}
|
|
||||||
return target[prop] ?? target.public[prop]
|
|
||||||
},
|
|
||||||
set (target, prop, value) {
|
|
||||||
if (prop === 'public' || prop === 'app') {
|
|
||||||
return false // Throws TypeError
|
|
||||||
}
|
|
||||||
target[prop] = value
|
|
||||||
target.public[prop] = value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
nuxtApp.provide('config', compatibilityConfig)
|
|
||||||
nuxtApp.$config = compatibilityConfig
|
|
||||||
}
|
|
||||||
return nuxtApp.$config as RuntimeConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-import equivalents for `vue-router`
|
|
||||||
export const useRouter = () => {
|
|
||||||
return useNuxtApp()?.nuxt2Context.app.router as VueRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
// This provides an equivalent interface to `vue-router` (unlike legacy implementation)
|
|
||||||
export const useRoute = () => {
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
|
|
||||||
if (!nuxtApp._route) {
|
|
||||||
Object.defineProperty(nuxtApp, '__route', {
|
|
||||||
get: () => nuxtApp.nuxt2Context.app.context.route
|
|
||||||
})
|
|
||||||
nuxtApp._route = reactive(nuxtApp.__route)
|
|
||||||
const router = useRouter()
|
|
||||||
router.afterEach(route => Object.assign(nuxtApp._route, route))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nuxtApp._route as Route
|
|
||||||
}
|
|
||||||
|
|
||||||
// payload.state is used for vuex by nuxt 2
|
|
||||||
export const useState = <T>(key: string, init?: (() => T)): Ref<T> => {
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
if (!nuxtApp.payload.useState) {
|
|
||||||
nuxtApp.payload.useState = {}
|
|
||||||
}
|
|
||||||
if (!isReactive(nuxtApp.payload.useState)) {
|
|
||||||
nuxtApp.payload.useState = reactive(nuxtApp.payload.useState)
|
|
||||||
}
|
|
||||||
|
|
||||||
// see @vuejs/composition-api reactivity tracking on a reactive object with set
|
|
||||||
if (!(key in nuxtApp.payload.useState)) {
|
|
||||||
set(nuxtApp.payload.useState, key, undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = toRef(nuxtApp.payload.useState, key)
|
|
||||||
if (state.value === undefined && init) {
|
|
||||||
state.value = init()
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
type Reffed<T extends Record<string, any>> = {
|
|
||||||
[P in keyof T]: T[P] extends Array<infer A> ? Ref<Array<Reffed<A>>> | Array<Reffed<A>> : T[P] extends Record<string, any> ? Reffed<T[P]> | Ref<Reffed<T[P]>> : T[P] | Ref<T[P]>
|
|
||||||
}
|
|
||||||
|
|
||||||
function unwrap (value: any): Record<string, any> {
|
|
||||||
if (!value || typeof value === 'string' || typeof value === 'boolean' || typeof value === 'number') { return value }
|
|
||||||
if (Array.isArray(value)) { return value.map(i => unwrap(i)) }
|
|
||||||
if (isRef(value)) { return unwrap(value.value) }
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
return Object.fromEntries(Object.entries(value).map(([key, value]) => [key, unwrap(value)]))
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
type AugmentedComponent = CombinedVueInstance<Vue, object, object, object, Record<never, any>> & {
|
|
||||||
_vueMeta?: boolean
|
|
||||||
$metaInfo?: MetaInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
/** internal */
|
|
||||||
function metaInfoFromOptions (metaOptions: Reffed<MetaInfo> | (() => Reffed<MetaInfo>)) {
|
|
||||||
return metaOptions instanceof Function ? metaOptions : () => metaOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useNuxt2Meta = (metaOptions: Reffed<MetaInfo> | (() => Reffed<MetaInfo>)) => {
|
|
||||||
let vm: AugmentedComponent | null = null
|
|
||||||
try {
|
|
||||||
vm = getCurrentInstance()!.proxy as AugmentedComponent
|
|
||||||
const meta = vm.$meta()
|
|
||||||
const $root = vm.$root
|
|
||||||
|
|
||||||
if (!vm._vueMeta) {
|
|
||||||
vm._vueMeta = true
|
|
||||||
|
|
||||||
let parent = vm.$parent as AugmentedComponent
|
|
||||||
while (parent && parent !== $root) {
|
|
||||||
if (parent._vueMeta === undefined) {
|
|
||||||
parent._vueMeta = false
|
|
||||||
}
|
|
||||||
parent = parent.$parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
vm.$options.head = vm.$options.head || {}
|
|
||||||
|
|
||||||
const unwatch = watch(metaInfoFromOptions(metaOptions), (metaInfo: MetaInfo) => {
|
|
||||||
vm.$metaInfo = {
|
|
||||||
...vm.$metaInfo || {},
|
|
||||||
...unwrap(metaInfo)
|
|
||||||
}
|
|
||||||
if (process.client) {
|
|
||||||
meta.refresh()
|
|
||||||
}
|
|
||||||
}, { immediate: true, deep: true })
|
|
||||||
|
|
||||||
onBeforeUnmount(unwatch)
|
|
||||||
} catch {
|
|
||||||
const app = (useNuxtApp().nuxt2Context as any).app
|
|
||||||
if (typeof app.head === 'function') {
|
|
||||||
const originalHead = app.head
|
|
||||||
app.head = function () {
|
|
||||||
const head = originalHead.call(this) || {}
|
|
||||||
return defu(unwrap(metaInfoFromOptions(metaOptions)()), head)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
app.head = defu(unwrap(metaInfoFromOptions(metaOptions)()), app.head)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AddRouteMiddlewareOptions {
|
|
||||||
global?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/** internal */
|
|
||||||
function convertToLegacyMiddleware (middleware) {
|
|
||||||
return async (ctx: any) => {
|
|
||||||
const result = await middleware(ctx.route, ctx.from)
|
|
||||||
if (result instanceof Error) {
|
|
||||||
return ctx.error(result)
|
|
||||||
}
|
|
||||||
if (result) {
|
|
||||||
return ctx.redirect(result)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isProcessingMiddleware = () => {
|
|
||||||
try {
|
|
||||||
if (useNuxtApp()._processingMiddleware) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Within an async middleware
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NavigateToOptions {
|
|
||||||
replace?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const navigateTo = (to: Route, options: NavigateToOptions = {}): Promise<Route | void> | Route => {
|
|
||||||
if (isProcessingMiddleware()) {
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
const router = useRouter()
|
|
||||||
if (process.server && useNuxtApp().ssrContext) {
|
|
||||||
// Server-side redirection using h3 res from ssrContext
|
|
||||||
const res = useNuxtApp().ssrContext?.res
|
|
||||||
const redirectLocation = router.resolve(to).route.fullPath
|
|
||||||
return sendRedirect(res, redirectLocation)
|
|
||||||
}
|
|
||||||
// Client-side redirection using vue-router
|
|
||||||
return options.replace ? router.replace(to) : router.push(to)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This will abort navigation within a Nuxt route middleware handler. */
|
|
||||||
export const abortNavigation = (err?: Error | string) => {
|
|
||||||
if (process.dev && !isProcessingMiddleware()) {
|
|
||||||
throw new Error('abortNavigation() is only usable inside a route middleware handler.')
|
|
||||||
}
|
|
||||||
if (err) {
|
|
||||||
throw err instanceof Error ? err : new Error(err)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteMiddlewareReturn = void | Error | string | Location | boolean
|
|
||||||
|
|
||||||
export interface RouteMiddleware {
|
|
||||||
(to: Route, from: Route): RouteMiddlewareReturn | Promise<RouteMiddlewareReturn>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defineNuxtRouteMiddleware = (middleware: RouteMiddleware) => middleware
|
|
||||||
|
|
||||||
interface AddRouteMiddleware {
|
|
||||||
(name: string, middleware: RouteMiddleware, options?: AddRouteMiddlewareOptions): void
|
|
||||||
(middleware: RouteMiddleware): void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const addRouteMiddleware: AddRouteMiddleware = (name: string | RouteMiddleware, middleware?: RouteMiddleware, options: AddRouteMiddlewareOptions = {}) => {
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
if (options.global || typeof name === 'function') {
|
|
||||||
nuxtApp._middleware.global.push(typeof name === 'function' ? name : middleware)
|
|
||||||
} else {
|
|
||||||
nuxtApp._middleware.named[name] = convertToLegacyMiddleware(middleware)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/app/composables/cookie.ts
|
|
@ -1,5 +0,0 @@
|
|||||||
export default (ctx) => {
|
|
||||||
if (ctx.ssrContext.error) {
|
|
||||||
ctx.error(ctx.ssrContext.error)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/app/composables/fetch.ts
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/head/runtime
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './app'
|
|
||||||
export * from './composables'
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/core/runtime/nitro
|
|
@ -1,7 +0,0 @@
|
|||||||
import { $fetch } from 'ohmyfetch'
|
|
||||||
|
|
||||||
if (!globalThis.$fetch) {
|
|
||||||
globalThis.$fetch = $fetch
|
|
||||||
}
|
|
||||||
|
|
||||||
export default () => {}
|
|
@ -1,51 +0,0 @@
|
|||||||
import { defineNuxtPlugin } from '#app'
|
|
||||||
|
|
||||||
const vueMetaRenderer = (nuxt) => {
|
|
||||||
const meta = nuxt.ssrContext.meta.inject({
|
|
||||||
isSSR: nuxt.ssrContext.nuxt.serverRendered,
|
|
||||||
ln: process.env.NODE_ENV === 'development'
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
htmlAttrs: meta.htmlAttrs.text(),
|
|
||||||
headAttrs: meta.headAttrs.text(),
|
|
||||||
headTags:
|
|
||||||
meta.title.text() + meta.base.text() +
|
|
||||||
meta.meta.text() + meta.link.text() +
|
|
||||||
meta.style.text() + meta.script.text() +
|
|
||||||
meta.noscript.text(),
|
|
||||||
bodyAttrs: meta.bodyAttrs.text(),
|
|
||||||
bodyScriptsPrepend:
|
|
||||||
meta.meta.text({ pbody: true }) + meta.link.text({ pbody: true }) +
|
|
||||||
meta.style.text({ pbody: true }) + meta.script.text({ pbody: true }) +
|
|
||||||
meta.noscript.text({ pbody: true }),
|
|
||||||
bodyScripts:
|
|
||||||
meta.meta.text({ body: true }) + meta.link.text({ body: true }) +
|
|
||||||
meta.style.text({ body: true }) + meta.script.text({ body: true }) +
|
|
||||||
meta.noscript.text({ body: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
|
||||||
const metaRenderers = [vueMetaRenderer]
|
|
||||||
|
|
||||||
nuxtApp.callHook('meta:register', metaRenderers)
|
|
||||||
|
|
||||||
nuxtApp.ssrContext.renderMeta = async () => {
|
|
||||||
const metadata = {
|
|
||||||
htmlAttrs: '',
|
|
||||||
headAttrs: '',
|
|
||||||
headTags: '',
|
|
||||||
bodyAttrs: '',
|
|
||||||
bodyScriptsPrepend: '',
|
|
||||||
bodyScripts: ''
|
|
||||||
}
|
|
||||||
for await (const renderer of metaRenderers) {
|
|
||||||
const result = await renderer(nuxtApp)
|
|
||||||
for (const key in result) {
|
|
||||||
metadata[key] += result[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return metadata
|
|
||||||
}
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
../../../nuxt3/src/app/composables/ssr.ts
|
|
@ -1 +0,0 @@
|
|||||||
export const AbortController = null
|
|
@ -1 +0,0 @@
|
|||||||
export const ReadableStream = null
|
|
@ -1,18 +0,0 @@
|
|||||||
export const URL = globalThis.URL
|
|
||||||
export const URLSearchParams = globalThis.URLSearchParams
|
|
||||||
|
|
||||||
function notSupported () {
|
|
||||||
throw new Error('[nuxt/vite] whatwg-url low level API is not supported yet!')
|
|
||||||
}
|
|
||||||
|
|
||||||
export const parseURL = notSupported
|
|
||||||
export const basicURLParse = notSupported
|
|
||||||
export const serializeURL = notSupported
|
|
||||||
export const serializeHost = notSupported
|
|
||||||
export const serializeInteger = notSupported
|
|
||||||
export const serializeURLOrigin = notSupported
|
|
||||||
export const setTheUsername = notSupported
|
|
||||||
export const setThePassword = notSupported
|
|
||||||
export const cannotHaveAUsernamePasswordPort = notSupported
|
|
||||||
export const percentDecodeBytes = notSupported
|
|
||||||
export const percentDecodeString = notSupported
|
|
60
packages/bridge/src/runtime/vue2-bridge.d.ts
vendored
60
packages/bridge/src/runtime/vue2-bridge.d.ts
vendored
@ -1,60 +0,0 @@
|
|||||||
import * as VueCapi from '@vue/composition-api'
|
|
||||||
|
|
||||||
declare module 'vue' {
|
|
||||||
export const EffectScope: typeof VueCapi['EffectScope']
|
|
||||||
export const computed: typeof VueCapi['computed']
|
|
||||||
export const createApp: typeof VueCapi['createApp']
|
|
||||||
export const createRef: typeof VueCapi['createRef']
|
|
||||||
export const customRef: typeof VueCapi['customRef']
|
|
||||||
export const defineAsyncComponent: typeof VueCapi['defineAsyncComponent']
|
|
||||||
export const defineComponent: typeof VueCapi['defineComponent']
|
|
||||||
export const del: typeof VueCapi['del']
|
|
||||||
export const effectScope: typeof VueCapi['effectScope']
|
|
||||||
export const getCurrentInstance: typeof VueCapi['getCurrentInstance']
|
|
||||||
export const getCurrentScope: typeof VueCapi['getCurrentScope']
|
|
||||||
export const h: typeof VueCapi['h']
|
|
||||||
export const inject: typeof VueCapi['inject']
|
|
||||||
export const isRaw: typeof VueCapi['isRaw']
|
|
||||||
export const isReactive: typeof VueCapi['isReactive']
|
|
||||||
export const isReadonly: typeof VueCapi['isReadonly']
|
|
||||||
export const isRef: typeof VueCapi['isRef']
|
|
||||||
export const markRaw: typeof VueCapi['markRaw']
|
|
||||||
export const nextTick: typeof VueCapi['nextTick']
|
|
||||||
export const onActivated: typeof VueCapi['onActivated']
|
|
||||||
export const onBeforeMount: typeof VueCapi['onBeforeMount']
|
|
||||||
export const onBeforeUnmount: typeof VueCapi['onBeforeUnmount']
|
|
||||||
export const onBeforeUpdate: typeof VueCapi['onBeforeUpdate']
|
|
||||||
export const onDeactivated: typeof VueCapi['onDeactivated']
|
|
||||||
export const onErrorCaptured: typeof VueCapi['onErrorCaptured']
|
|
||||||
export const onMounted: typeof VueCapi['onMounted']
|
|
||||||
export const onScopeDispose: typeof VueCapi['onScopeDispose']
|
|
||||||
export const onServerPrefetch: typeof VueCapi['onServerPrefetch']
|
|
||||||
export const onUnmounted: typeof VueCapi['onUnmounted']
|
|
||||||
export const onUpdated: typeof VueCapi['onUpdated']
|
|
||||||
export const provide: typeof VueCapi['provide']
|
|
||||||
export const proxyRefs: typeof VueCapi['proxyRefs']
|
|
||||||
export const reactive: typeof VueCapi['reactive']
|
|
||||||
export const readonly: typeof VueCapi['readonly']
|
|
||||||
export const ref: typeof VueCapi['ref']
|
|
||||||
export const set: typeof VueCapi['set']
|
|
||||||
export const shallowReactive: typeof VueCapi['shallowReactive']
|
|
||||||
export const shallowReadonly: typeof VueCapi['shallowReadonly']
|
|
||||||
export const shallowRef: typeof VueCapi['shallowRef']
|
|
||||||
export const toRaw: typeof VueCapi['toRaw']
|
|
||||||
export const toRef: typeof VueCapi['toRef']
|
|
||||||
export const toRefs: typeof VueCapi['toRefs']
|
|
||||||
export const triggerRef: typeof VueCapi['triggerRef']
|
|
||||||
export const unref: typeof VueCapi['unref']
|
|
||||||
export const useAttrs: typeof VueCapi['useAttrs']
|
|
||||||
export const useCSSModule: typeof VueCapi['useCSSModule']
|
|
||||||
export const useCssModule: typeof VueCapi['useCssModule']
|
|
||||||
export const useSlots: typeof VueCapi['useSlots']
|
|
||||||
export const warn: typeof VueCapi['warn']
|
|
||||||
export const watch: typeof VueCapi['watch']
|
|
||||||
export const watchEffect: typeof VueCapi['watchEffect']
|
|
||||||
export const watchPostEffect: typeof VueCapi['watchPostEffect']
|
|
||||||
export const watchSyncEffect: typeof VueCapi['watchSyncEffect']
|
|
||||||
export const isFunction: (fn: unknown) => boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export {}
|
|
@ -1,14 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
export { EffectScope, computed, createApp, createRef, customRef, defineAsyncComponent, defineComponent, del, effectScope, getCurrentInstance, getCurrentScope, h, inject, isRaw, isReactive, isReadonly, isRef, markRaw, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onScopeDispose, onServerPrefetch, onUnmounted, onUpdated, provide, proxyRefs, reactive, readonly, ref, set, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, triggerRef, unref, useAttrs, useCSSModule, useCssModule, useSlots, warn, watch, watchEffect, watchPostEffect, watchSyncEffect } from '@vue/composition-api'
|
|
||||||
|
|
||||||
export const isFunction = fn => fn instanceof Function
|
|
||||||
|
|
||||||
export { Vue as default }
|
|
||||||
|
|
||||||
// mock for vue-demi
|
|
||||||
export const Vue2 = Vue
|
|
||||||
export const isVue2 = true
|
|
||||||
export const isVue3 = false
|
|
||||||
export const install = () => {}
|
|
||||||
export const version = Vue.version
|
|
@ -1,16 +0,0 @@
|
|||||||
import { useNuxt, installModule } from '@nuxt/kit'
|
|
||||||
import scriptSetupPlugin from 'unplugin-vue2-script-setup/nuxt'
|
|
||||||
import type { ScriptSetupOptions } from '../types'
|
|
||||||
|
|
||||||
export const setupScriptSetup = async (options: ScriptSetupOptions) => {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
const config = options === true ? {} : options
|
|
||||||
|
|
||||||
nuxt.hook('prepare:types', ({ references }) => {
|
|
||||||
references.push({
|
|
||||||
types: 'unplugin-vue2-script-setup/types'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
await installModule(scriptSetupPlugin, config)
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { useNuxt } from '@nuxt/kit'
|
|
||||||
import { addModuleTranspiles } from '../../nuxt3/src/core/modules'
|
|
||||||
|
|
||||||
export const setupTranspile = () => {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
nuxt.hook('modules:done', () => {
|
|
||||||
addModuleTranspiles({
|
|
||||||
additionalModules: ['@nuxt/bridge-edge']
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import { createRequire } from 'module'
|
|
||||||
import { extendWebpackConfig, useNuxt } from '@nuxt/kit'
|
|
||||||
|
|
||||||
const extensions = ['ts', 'tsx', 'cts', 'mts']
|
|
||||||
const typescriptRE = /\.[cm]?tsx?$/
|
|
||||||
|
|
||||||
export function setupTypescript () {
|
|
||||||
const nuxt = useNuxt()
|
|
||||||
|
|
||||||
nuxt.options.extensions.push(...extensions)
|
|
||||||
nuxt.options.build.additionalExtensions.push(...extensions)
|
|
||||||
|
|
||||||
nuxt.options.build.babel.plugins = nuxt.options.build.babel.plugins || []
|
|
||||||
|
|
||||||
// Error if `@nuxt/typescript-build` is added
|
|
||||||
if (nuxt.options.buildModules.includes('@nuxt/typescript-build')) {
|
|
||||||
throw new Error('Please remove `@nuxt/typescript-build` from `buildModules` or set `bridge.typescript: false` to avoid conflict with bridge.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const _require = createRequire(import.meta.url)
|
|
||||||
nuxt.options.build.babel.plugins.unshift(
|
|
||||||
_require.resolve('@babel/plugin-proposal-optional-chaining'),
|
|
||||||
_require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
|
||||||
_require.resolve('@babel/plugin-transform-typescript')
|
|
||||||
)
|
|
||||||
|
|
||||||
extendWebpackConfig((config) => {
|
|
||||||
config.resolve.extensions!.push(...extensions.map(e => `.${e}`))
|
|
||||||
const babelRule: any = config.module.rules.find((rule: any) => rule.test?.test('test.js'))
|
|
||||||
config.module.rules.unshift({
|
|
||||||
...babelRule,
|
|
||||||
test: typescriptRE
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
import { resolve } from 'pathe'
|
|
||||||
import * as vite from 'vite'
|
|
||||||
import { createVuePlugin } from 'vite-plugin-vue2'
|
|
||||||
import PluginLegacy from '@vitejs/plugin-legacy'
|
|
||||||
import { logger } from '@nuxt/kit'
|
|
||||||
import { joinURL } from 'ufo'
|
|
||||||
import { devStyleSSRPlugin } from '../../../vite/src/plugins/dev-ssr-css'
|
|
||||||
import { RelativeAssetPlugin } from '../../../vite/src/plugins/dynamic-base'
|
|
||||||
import { jsxPlugin } from './plugins/jsx'
|
|
||||||
import { ViteBuildContext, ViteOptions } from './types'
|
|
||||||
|
|
||||||
export async function buildClient (ctx: ViteBuildContext) {
|
|
||||||
const alias = {
|
|
||||||
'#nitro': resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs')
|
|
||||||
}
|
|
||||||
for (const p of ctx.builder.plugins) {
|
|
||||||
alias[p.name] = p.mode === 'server'
|
|
||||||
? `defaultexport:${resolve(ctx.nuxt.options.buildDir, 'empty.js')}`
|
|
||||||
: `defaultexport:${p.src}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
|
||||||
define: {
|
|
||||||
'process.client': true,
|
|
||||||
'process.server': false,
|
|
||||||
'process.static': false,
|
|
||||||
'module.hot': false
|
|
||||||
},
|
|
||||||
cacheDir: resolve(ctx.nuxt.options.rootDir, 'node_modules/.cache/vite/client'),
|
|
||||||
resolve: {
|
|
||||||
alias
|
|
||||||
},
|
|
||||||
build: {
|
|
||||||
rollupOptions: {
|
|
||||||
input: resolve(ctx.nuxt.options.buildDir, 'client.js')
|
|
||||||
},
|
|
||||||
manifest: true,
|
|
||||||
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/client')
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
jsxPlugin(),
|
|
||||||
createVuePlugin(ctx.config.vue),
|
|
||||||
PluginLegacy(),
|
|
||||||
RelativeAssetPlugin(),
|
|
||||||
devStyleSSRPlugin({
|
|
||||||
rootDir: ctx.nuxt.options.rootDir,
|
|
||||||
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir)
|
|
||||||
})
|
|
||||||
],
|
|
||||||
server: {
|
|
||||||
middlewareMode: true
|
|
||||||
}
|
|
||||||
} as ViteOptions)
|
|
||||||
|
|
||||||
await ctx.nuxt.callHook('vite:extendConfig', clientConfig, { isClient: true, isServer: false })
|
|
||||||
|
|
||||||
// Production build
|
|
||||||
if (!ctx.nuxt.options.dev) {
|
|
||||||
const start = Date.now()
|
|
||||||
logger.info('Building client...')
|
|
||||||
await vite.build(clientConfig)
|
|
||||||
logger.success(`Client built in ${Date.now() - start}ms`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create development server
|
|
||||||
const viteServer = await vite.createServer(clientConfig)
|
|
||||||
await ctx.nuxt.callHook('vite:serverCreated', viteServer)
|
|
||||||
|
|
||||||
const viteMiddleware = (req, res, next) => {
|
|
||||||
// Workaround: vite devmiddleware modifies req.url
|
|
||||||
const originalURL = req.url
|
|
||||||
viteServer.middlewares.handle(req, res, (err) => {
|
|
||||||
req.url = originalURL
|
|
||||||
next(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
await ctx.nuxt.callHook('server:devMiddleware', viteMiddleware)
|
|
||||||
|
|
||||||
ctx.nuxt.hook('close', async () => {
|
|
||||||
await viteServer.close()
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import createResolver from 'postcss-import-resolver'
|
|
||||||
import defu from 'defu'
|
|
||||||
import type { Nuxt, ViteOptions } from './types'
|
|
||||||
|
|
||||||
// Ref: https://github.com/nuxt/nuxt.js/blob/dev/packages/webpack/src/utils/postcss.js
|
|
||||||
|
|
||||||
export function resolveCSSOptions (nuxt: Nuxt): ViteOptions['css'] {
|
|
||||||
const css: ViteOptions['css'] = {
|
|
||||||
postcss: {
|
|
||||||
plugins: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const plugins = defu(nuxt.options.build.postcss.plugins, {
|
|
||||||
// https://github.com/postcss/postcss-import
|
|
||||||
'postcss-import': {
|
|
||||||
resolve: createResolver({
|
|
||||||
alias: { ...nuxt.options.alias },
|
|
||||||
modules: [
|
|
||||||
nuxt.options.srcDir,
|
|
||||||
nuxt.options.rootDir,
|
|
||||||
...nuxt.options.modulesDir
|
|
||||||
]
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// https://github.com/postcss/postcss-url
|
|
||||||
'postcss-url': {},
|
|
||||||
|
|
||||||
// https://github.com/csstools/postcss-preset-env
|
|
||||||
'postcss-preset-env': nuxt.options.build.postcss.preset || {}
|
|
||||||
})
|
|
||||||
|
|
||||||
for (const name in plugins) {
|
|
||||||
const opts = plugins[name]
|
|
||||||
if (!opts) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const plugin = nuxt.resolver.requireModule(name)
|
|
||||||
// @ts-ignore
|
|
||||||
css.postcss.plugins.push(plugin(opts))
|
|
||||||
}
|
|
||||||
|
|
||||||
return css
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
import { resolve } from 'pathe'
|
|
||||||
import fse from 'fs-extra'
|
|
||||||
import { uniq, isJS, isCSS, hash } from '../../../vite/src/utils'
|
|
||||||
import { ViteBuildContext } from './types'
|
|
||||||
|
|
||||||
const DEFAULT_APP_TEMPLATE = `
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html {{ HTML_ATTRS }}>
|
|
||||||
<head {{ HEAD_ATTRS }}>
|
|
||||||
{{ HEAD }}
|
|
||||||
</head>
|
|
||||||
<body {{ BODY_ATTRS }}>
|
|
||||||
{{ APP }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
|
|
||||||
export async function prepareManifests (ctx: ViteBuildContext) {
|
|
||||||
const rDist = (...args: string[]): string => resolve(ctx.nuxt.options.buildDir, 'dist', ...args)
|
|
||||||
await fse.mkdirp(rDist('server'))
|
|
||||||
|
|
||||||
const customAppTemplateFile = resolve(ctx.nuxt.options.srcDir, 'app.html')
|
|
||||||
const APP_TEMPLATE = fse.existsSync(customAppTemplateFile)
|
|
||||||
? (await fse.readFile(customAppTemplateFile, 'utf-8'))
|
|
||||||
: DEFAULT_APP_TEMPLATE
|
|
||||||
|
|
||||||
const DEV_TEMPLATE = APP_TEMPLATE
|
|
||||||
.replace(
|
|
||||||
'</body>',
|
|
||||||
'<script type="module" src="/@vite/client"></script><script type="module" src="/.nuxt/client.js"></script></body>'
|
|
||||||
)
|
|
||||||
const SPA_TEMPLATE = ctx.nuxt.options.dev ? DEV_TEMPLATE : APP_TEMPLATE
|
|
||||||
const SSR_TEMPLATE = ctx.nuxt.options.dev ? DEV_TEMPLATE : APP_TEMPLATE
|
|
||||||
|
|
||||||
await fse.writeFile(rDist('server/index.ssr.html'), SSR_TEMPLATE)
|
|
||||||
await fse.writeFile(rDist('server/index.spa.html'), SPA_TEMPLATE)
|
|
||||||
|
|
||||||
if (ctx.nuxt.options.dev) {
|
|
||||||
await stubManifest(ctx)
|
|
||||||
} else {
|
|
||||||
await generateBuildManifest(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert vite's manifest to webpack style
|
|
||||||
export async function generateBuildManifest (ctx: ViteBuildContext) {
|
|
||||||
const rDist = (...args: string[]): string => resolve(ctx.nuxt.options.buildDir, 'dist', ...args)
|
|
||||||
|
|
||||||
const viteClientManifest = await fse.readJSON(rDist('client/manifest.json'))
|
|
||||||
const clientEntries = Object.entries(viteClientManifest)
|
|
||||||
|
|
||||||
const asyncEntries = uniq(clientEntries.filter((id: any) => id[1].isDynamicEntry).flatMap(getModuleIds)).filter(Boolean)
|
|
||||||
const initialEntries = uniq(clientEntries.filter((id: any) => !id[1].isDynamicEntry).flatMap(getModuleIds)).filter(Boolean)
|
|
||||||
const initialJs = initialEntries.filter(isJS)
|
|
||||||
const initialAssets = initialEntries.filter(isCSS)
|
|
||||||
|
|
||||||
// Search for polyfill file, we don't include it in the client entry
|
|
||||||
const polyfillName = initialEntries.find(id => id.startsWith('polyfills-legacy.'))
|
|
||||||
const polyfill = await fse.readFile(rDist('client/' + polyfillName), 'utf-8')
|
|
||||||
|
|
||||||
// @vitejs/plugin-legacy uses SystemJS which need to call `System.import` to load modules
|
|
||||||
const clientImports = initialJs.filter(id => id !== polyfillName)
|
|
||||||
const clientEntryCode = [
|
|
||||||
polyfill,
|
|
||||||
'var appConfig = window?.__NUXT__?.config.app || {}',
|
|
||||||
'var publicBase = appConfig.cdnURL || ("." + appConfig.baseURL)',
|
|
||||||
`var imports = ${JSON.stringify(clientImports)};`,
|
|
||||||
'imports.reduce((p, id) => p.then(() => System.import(publicBase + appConfig.buildAssetsDir.slice(1) + id)), Promise.resolve())'
|
|
||||||
].join('\n')
|
|
||||||
const clientEntryName = 'entry-legacy.' + hash(clientEntryCode) + '.js'
|
|
||||||
|
|
||||||
const clientManifest = {
|
|
||||||
// This publicPath will be ignored by Nitro and computed dynamically
|
|
||||||
publicPath: ctx.nuxt.options.app.buildAssetsDir,
|
|
||||||
all: uniq([
|
|
||||||
clientEntryName,
|
|
||||||
...clientEntries.flatMap(getModuleIds)
|
|
||||||
]).filter(Boolean),
|
|
||||||
initial: [
|
|
||||||
clientEntryName,
|
|
||||||
...initialAssets
|
|
||||||
].filter(Boolean),
|
|
||||||
async: [
|
|
||||||
// We move initial entries to the client entry
|
|
||||||
...initialJs,
|
|
||||||
...asyncEntries
|
|
||||||
].filter(Boolean),
|
|
||||||
modules: {},
|
|
||||||
assetsMapping: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverManifest = {
|
|
||||||
entry: 'server.js',
|
|
||||||
files: {
|
|
||||||
'server.js': 'server.js',
|
|
||||||
...Object.fromEntries(clientEntries.map(([id, entry]) => [id, (entry as any).file]))
|
|
||||||
},
|
|
||||||
maps: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
await fse.writeFile(rDist('client', clientEntryName), clientEntryCode, 'utf-8')
|
|
||||||
|
|
||||||
await writeClientManifest(clientManifest, ctx.nuxt.options.buildDir)
|
|
||||||
await writeServerManifest(serverManifest, ctx.nuxt.options.buildDir)
|
|
||||||
|
|
||||||
// Remove SSR manifest from public client dir
|
|
||||||
await fse.remove(rDist('client/manifest.json'))
|
|
||||||
await fse.remove(rDist('client/ssr-manifest.json'))
|
|
||||||
}
|
|
||||||
|
|
||||||
// stub manifest on dev
|
|
||||||
export async function stubManifest (ctx: ViteBuildContext) {
|
|
||||||
const clientManifest = {
|
|
||||||
publicPath: '',
|
|
||||||
all: [
|
|
||||||
'empty.js'
|
|
||||||
],
|
|
||||||
initial: [
|
|
||||||
'empty.js'
|
|
||||||
],
|
|
||||||
async: [],
|
|
||||||
modules: {},
|
|
||||||
assetsMapping: {}
|
|
||||||
}
|
|
||||||
const serverManifest = {
|
|
||||||
entry: 'server.js',
|
|
||||||
files: {
|
|
||||||
'server.js': 'server.js'
|
|
||||||
},
|
|
||||||
maps: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeClientManifest(clientManifest, ctx.nuxt.options.buildDir)
|
|
||||||
await writeServerManifest(serverManifest, ctx.nuxt.options.buildDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateDevSSRManifest (ctx: ViteBuildContext, extraEntries: string[] = []) {
|
|
||||||
const entires = [
|
|
||||||
'@vite/client',
|
|
||||||
'entry.mjs',
|
|
||||||
...extraEntries
|
|
||||||
]
|
|
||||||
|
|
||||||
const clientManifest = {
|
|
||||||
publicPath: '',
|
|
||||||
all: entires,
|
|
||||||
initial: entires,
|
|
||||||
async: [],
|
|
||||||
modules: {},
|
|
||||||
assetsMapping: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeClientManifest(clientManifest, ctx.nuxt.options.buildDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeServerManifest (serverManifest: any, buildDir: string) {
|
|
||||||
const serverManifestJSON = JSON.stringify(serverManifest, null, 2)
|
|
||||||
await fse.writeFile(resolve(buildDir, 'dist/server/server.manifest.json'), serverManifestJSON, 'utf-8')
|
|
||||||
await fse.writeFile(resolve(buildDir, 'dist/server/server.manifest.mjs'), `export default ${serverManifestJSON}`, 'utf-8')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeClientManifest (clientManifest: any, buildDir: string) {
|
|
||||||
const clientManifestJSON = JSON.stringify(clientManifest, null, 2)
|
|
||||||
await fse.writeFile(resolve(buildDir, 'dist/server/client.manifest.json'), clientManifestJSON, 'utf-8')
|
|
||||||
await fse.writeFile(resolve(buildDir, 'dist/server/client.manifest.mjs'), `export default ${clientManifestJSON}`, 'utf-8')
|
|
||||||
}
|
|
||||||
|
|
||||||
function getModuleIds ([, value]: [string, any]) {
|
|
||||||
if (!value) { return [] }
|
|
||||||
// Only include legacy and css ids
|
|
||||||
return [value.file, ...value.css || []].filter(id => isCSS(id) || id.match(/-legacy\./))
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import { logger, addPluginTemplate, defineNuxtModule, addTemplate } from '@nuxt/kit'
|
|
||||||
import { publicPathTemplate, clientConfigTemplate } from '../../../nuxt3/src/core/templates'
|
|
||||||
import { version } from '../../package.json'
|
|
||||||
import { middlewareTemplate, storeTemplate } from './templates'
|
|
||||||
import type { ViteOptions } from './types'
|
|
||||||
|
|
||||||
export default defineNuxtModule<ViteOptions>({
|
|
||||||
meta: {
|
|
||||||
name: 'nuxt-bridge:vite',
|
|
||||||
version,
|
|
||||||
configKey: 'vite'
|
|
||||||
},
|
|
||||||
defaults: {},
|
|
||||||
setup (viteOptions, nuxt) {
|
|
||||||
nuxt.options.cli.badgeMessages.push(`⚡ Vite Mode Enabled (v${version})`)
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
if (viteOptions.experimentWarning !== false && !nuxt.options.test) {
|
|
||||||
logger.log(
|
|
||||||
'🧪 Vite mode is experimental and some nuxt modules might be incompatible\n',
|
|
||||||
' If found a bug, please report via https://github.com/nuxt/framework/issues with a minimal reproduction.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable loading-screen because why have it!
|
|
||||||
// @ts-expect-error
|
|
||||||
nuxt.options.build.loadingScreen = false
|
|
||||||
// @ts-expect-error
|
|
||||||
nuxt.options.build.indicator = false
|
|
||||||
nuxt.options._modules = nuxt.options._modules
|
|
||||||
.filter(m => !(Array.isArray(m) && m[0] === '@nuxt/loading-screen'))
|
|
||||||
|
|
||||||
// Mask nuxt-vite to avoid other modules depending on it's existence
|
|
||||||
// TODO: Move to kit
|
|
||||||
const getModuleName = (m) => {
|
|
||||||
if (Array.isArray(m)) { m = m[0] }
|
|
||||||
return m.meta ? m.meta.name : m
|
|
||||||
}
|
|
||||||
const filterModule = modules => modules.filter(m => getModuleName(m) !== 'nuxt-bridge:vite')
|
|
||||||
nuxt.options.modules = filterModule(nuxt.options.modules)
|
|
||||||
nuxt.options.buildModules = filterModule(nuxt.options.buildModules)
|
|
||||||
|
|
||||||
if (nuxt.options.store) {
|
|
||||||
addPluginTemplate(storeTemplate)
|
|
||||||
}
|
|
||||||
addPluginTemplate(middlewareTemplate)
|
|
||||||
|
|
||||||
addTemplate(clientConfigTemplate)
|
|
||||||
addTemplate({
|
|
||||||
...publicPathTemplate,
|
|
||||||
options: { nuxt }
|
|
||||||
})
|
|
||||||
|
|
||||||
nuxt.hook('builder:prepared', async (builder) => {
|
|
||||||
if (nuxt.options._prepare) { return }
|
|
||||||
builder.bundleBuilder.close()
|
|
||||||
delete builder.bundleBuilder
|
|
||||||
const { ViteBuilder } = await import('./vite')
|
|
||||||
builder.bundleBuilder = new ViteBuilder(builder)
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove templates from nuxt-app
|
|
||||||
nuxt.hook('build:templates', (templates) => {
|
|
||||||
const templatesFiles = templates.templatesFiles.filter((template) => {
|
|
||||||
return !['store.js', 'middleware.js'].includes(template.dst)
|
|
||||||
})
|
|
||||||
templates.templatesFiles.length = 0
|
|
||||||
templates.templatesFiles.push(...templatesFiles)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,37 +0,0 @@
|
|||||||
import type { Plugin } from 'vite'
|
|
||||||
import fse from 'fs-extra'
|
|
||||||
import { findExports } from 'mlly'
|
|
||||||
|
|
||||||
const PREFIX = 'defaultexport:'
|
|
||||||
const hasPrefix = (id: string = '') => id.startsWith(PREFIX)
|
|
||||||
const removePrefix = (id: string = '') => hasPrefix(id) ? id.substr(PREFIX.length) : id
|
|
||||||
|
|
||||||
const addDefaultExport = (code: string = '') => code + '\n\n' + 'export default () => {}'
|
|
||||||
|
|
||||||
export function defaultExportPlugin () {
|
|
||||||
return <Plugin>{
|
|
||||||
name: 'nuxt:default-export',
|
|
||||||
enforce: 'pre',
|
|
||||||
resolveId (id, importer) {
|
|
||||||
if (hasPrefix(id)) {
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
if (importer && hasPrefix(importer)) {
|
|
||||||
return this.resolve(id, removePrefix(importer))
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
|
|
||||||
async load (id) {
|
|
||||||
if (hasPrefix(id)) {
|
|
||||||
let code = await fse.readFile(removePrefix(id), 'utf8')
|
|
||||||
const exports = findExports(code)
|
|
||||||
if (!exports.find(i => i.names.includes('default'))) {
|
|
||||||
code = addDefaultExport(code)
|
|
||||||
}
|
|
||||||
return { map: null, code }
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import type { Plugin } from 'vite'
|
|
||||||
|
|
||||||
const needsJsxProcessing = (id: string = '') =>
|
|
||||||
!id.includes('node_modules') && ['.vue', '.jsx', '.tsx'].some(extension => id.includes(extension))
|
|
||||||
|
|
||||||
export function jsxPlugin () {
|
|
||||||
return <Plugin>{
|
|
||||||
name: 'nuxt:jsx',
|
|
||||||
transform (code, id) {
|
|
||||||
if (!needsJsxProcessing(id)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: code.replace(/render\s*\(\s*\)\s*\{/g, 'render(h){'),
|
|
||||||
map: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import type { Plugin } from 'vite'
|
|
||||||
|
|
||||||
export function replace (replacements: Record<string, string>) {
|
|
||||||
return <Plugin>{
|
|
||||||
name: 'nuxt:replace',
|
|
||||||
transform (code) {
|
|
||||||
Object.entries(replacements).forEach(([key, value]) => {
|
|
||||||
const escapedKey = key.replace(/\./g, '\\.')
|
|
||||||
code = code.replace(new RegExp(escapedKey, 'g'), value)
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
code,
|
|
||||||
map: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
import { resolve } from 'pathe'
|
|
||||||
import * as vite from 'vite'
|
|
||||||
import { createVuePlugin } from 'vite-plugin-vue2'
|
|
||||||
import { logger } from '@nuxt/kit'
|
|
||||||
import fse from 'fs-extra'
|
|
||||||
import { debounce } from 'perfect-debounce'
|
|
||||||
import { bundleRequest } from '../../../vite/src/dev-bundler'
|
|
||||||
import { isCSS } from '../../../vite/src/utils'
|
|
||||||
import { wpfs } from './utils/wpfs'
|
|
||||||
import { ViteBuildContext, ViteOptions } from './types'
|
|
||||||
import { jsxPlugin } from './plugins/jsx'
|
|
||||||
import { generateDevSSRManifest } from './manifest'
|
|
||||||
|
|
||||||
export async function buildServer (ctx: ViteBuildContext) {
|
|
||||||
// Workaround to disable HMR
|
|
||||||
const _env = process.env.NODE_ENV
|
|
||||||
process.env.NODE_ENV = 'production'
|
|
||||||
const vuePlugin = createVuePlugin(ctx.config.vue)
|
|
||||||
process.env.NODE_ENV = _env
|
|
||||||
|
|
||||||
const alias = {}
|
|
||||||
for (const p of ctx.builder.plugins) {
|
|
||||||
alias[p.name] = p.mode === 'client'
|
|
||||||
? `defaultexport:${resolve(ctx.nuxt.options.buildDir, 'empty.js')}`
|
|
||||||
: `defaultexport:${p.src}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
|
||||||
define: {
|
|
||||||
'process.server': true,
|
|
||||||
'process.client': false,
|
|
||||||
'process.static': false,
|
|
||||||
'typeof window': '"undefined"',
|
|
||||||
'typeof document': '"undefined"',
|
|
||||||
'typeof navigator': '"undefined"',
|
|
||||||
'typeof location': '"undefined"',
|
|
||||||
'typeof XMLHttpRequest': '"undefined"'
|
|
||||||
},
|
|
||||||
cacheDir: resolve(ctx.nuxt.options.rootDir, 'node_modules/.cache/vite/server'),
|
|
||||||
resolve: {
|
|
||||||
alias
|
|
||||||
},
|
|
||||||
ssr: {
|
|
||||||
external: [
|
|
||||||
'axios'
|
|
||||||
],
|
|
||||||
noExternal: [
|
|
||||||
// TODO: Use externality for production (rollup) build
|
|
||||||
/\/esm\/.*\.js$/,
|
|
||||||
/\.(es|esm|esm-browser|esm-bundler).js$/,
|
|
||||||
'#app',
|
|
||||||
/@nuxt\/nitro\/(dist|src)/,
|
|
||||||
...ctx.nuxt.options.build.transpile.filter(i => typeof i === 'string')
|
|
||||||
]
|
|
||||||
},
|
|
||||||
build: {
|
|
||||||
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/server'),
|
|
||||||
ssr: ctx.nuxt.options.ssr ?? true,
|
|
||||||
ssrManifest: true,
|
|
||||||
rollupOptions: {
|
|
||||||
external: ['#nitro'],
|
|
||||||
input: resolve(ctx.nuxt.options.buildDir, 'server.js'),
|
|
||||||
output: {
|
|
||||||
entryFileNames: 'server.mjs',
|
|
||||||
chunkFileNames: 'chunks/[name].mjs',
|
|
||||||
preferConst: true,
|
|
||||||
format: 'module'
|
|
||||||
},
|
|
||||||
onwarn (warning, rollupWarn) {
|
|
||||||
if (!['UNUSED_EXTERNAL_IMPORT'].includes(warning.code)) {
|
|
||||||
rollupWarn(warning)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
// https://github.com/vitest-dev/vitest/issues/229#issuecomment-1002685027
|
|
||||||
preTransformRequests: false
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
jsxPlugin(),
|
|
||||||
vuePlugin
|
|
||||||
]
|
|
||||||
} as ViteOptions)
|
|
||||||
|
|
||||||
await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true })
|
|
||||||
|
|
||||||
const onBuild = () => ctx.nuxt.callHook('build:resources', wpfs)
|
|
||||||
|
|
||||||
// Production build
|
|
||||||
if (!ctx.nuxt.options.dev) {
|
|
||||||
const start = Date.now()
|
|
||||||
logger.info('Building server...')
|
|
||||||
await vite.build(serverConfig)
|
|
||||||
await onBuild()
|
|
||||||
logger.success(`Server built in ${Date.now() - start}ms`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start development server
|
|
||||||
const viteServer = await vite.createServer(serverConfig)
|
|
||||||
ctx.nuxt.hook('close', () => viteServer.close())
|
|
||||||
|
|
||||||
// Invalidate virtual modules when templates are re-generated
|
|
||||||
ctx.nuxt.hook('app:templatesGenerated', () => {
|
|
||||||
for (const [id, mod] of viteServer.moduleGraph.idToModuleMap) {
|
|
||||||
if (id.startsWith('\x00virtual:')) {
|
|
||||||
viteServer.moduleGraph.invalidateModule(mod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Initialize plugins
|
|
||||||
await viteServer.pluginContainer.buildStart({})
|
|
||||||
|
|
||||||
// Generate manifest files
|
|
||||||
await fse.writeFile(resolve(ctx.nuxt.options.buildDir, 'dist/server/ssr-manifest.json'), JSON.stringify({}, null, 2), 'utf-8')
|
|
||||||
await generateDevSSRManifest(ctx)
|
|
||||||
|
|
||||||
// Build and watch
|
|
||||||
const _doBuild = async () => {
|
|
||||||
const start = Date.now()
|
|
||||||
const { code, ids } = await bundleRequest({ viteServer }, '/.nuxt/server.js')
|
|
||||||
// Have CSS in the manifest to prevent FOUC on dev SSR
|
|
||||||
await generateDevSSRManifest(ctx, ids.filter(isCSS).map(i => '../' + i.slice(1)))
|
|
||||||
await fse.writeFile(resolve(ctx.nuxt.options.buildDir, 'dist/server/server.mjs'), code, 'utf-8')
|
|
||||||
const time = (Date.now() - start)
|
|
||||||
consola.info(`Server built in ${time}ms`)
|
|
||||||
await onBuild()
|
|
||||||
}
|
|
||||||
const doBuild = debounce(_doBuild)
|
|
||||||
|
|
||||||
// Initial build
|
|
||||||
await _doBuild()
|
|
||||||
|
|
||||||
// Watch
|
|
||||||
viteServer.watcher.on('all', (_event, file) => {
|
|
||||||
if (file.indexOf(ctx.nuxt.options.buildDir) === 0) { return }
|
|
||||||
doBuild()
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
import hash from 'hash-sum'
|
|
||||||
import { resolve } from 'pathe'
|
|
||||||
|
|
||||||
import type { Nuxt, NuxtApp } from '@nuxt/schema'
|
|
||||||
import { genImport, genObjectFromRawEntries } from 'knitwork'
|
|
||||||
|
|
||||||
type TemplateContext = {
|
|
||||||
nuxt: Nuxt;
|
|
||||||
app: NuxtApp & { templateVars: Record<string, any> };
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use an alias
|
|
||||||
export const middlewareTemplate = {
|
|
||||||
filename: 'middleware.js',
|
|
||||||
getContents (ctx: TemplateContext) {
|
|
||||||
const { dir, router: { middleware }, srcDir } = ctx.nuxt.options
|
|
||||||
const _middleware = ((typeof middleware !== 'undefined' && middleware) || []).map((m) => {
|
|
||||||
// Normalize string middleware
|
|
||||||
if (typeof m === 'string') {
|
|
||||||
m = { src: m }
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
filePath: resolve(srcDir, dir.middleware, m.src),
|
|
||||||
id: m.name || m.src.replace(/[\\/]/g, '/').replace(/\.(js|ts)$/, '')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return `${_middleware.map(m => genImport(m.filePath, `$${hash(m.id)}`)).join('\n')}
|
|
||||||
const middleware = ${genObjectFromRawEntries(_middleware.map(m => [m.id, `$${hash(m.id)}`]))}
|
|
||||||
export default middleware`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const storeTemplate = {
|
|
||||||
filename: 'store.js',
|
|
||||||
getContents (ctx: TemplateContext) {
|
|
||||||
const { dir, srcDir } = ctx.nuxt.options
|
|
||||||
const { templateVars: { storeModules = [] } } = ctx.app
|
|
||||||
const _storeModules = storeModules.map(s => ({
|
|
||||||
filePath: resolve(srcDir, dir.store, s.src),
|
|
||||||
id: (s.src
|
|
||||||
.replace(/\.(js|ts)$/, '')
|
|
||||||
.replace(/[\\/]/g, '/')
|
|
||||||
.replace(/index/, '')
|
|
||||||
) || 'root'
|
|
||||||
}))
|
|
||||||
|
|
||||||
return `import Vue from 'vue'
|
|
||||||
import Vuex from 'vuex'
|
|
||||||
${_storeModules.map(s => genImport(s.filePath, { name: '*', as: `$${hash(s.id)}` })).join('\n')}
|
|
||||||
Vue.use(Vuex)
|
|
||||||
|
|
||||||
const VUEX_PROPERTIES = ['state', 'getters', 'actions', 'mutations']
|
|
||||||
|
|
||||||
const storeModules = ${genObjectFromRawEntries(_storeModules.map(m => [m.id, `$${hash(m.id)}`]))}
|
|
||||||
|
|
||||||
export function createStore() {
|
|
||||||
let store = normalizeRoot(storeModules.root || {})
|
|
||||||
delete storeModules.root
|
|
||||||
for (const id in storeModules) {
|
|
||||||
resolveStoreModules(store, storeModules[id], id)
|
|
||||||
}
|
|
||||||
if (typeof store === 'function') {
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
return new Vuex.Store(Object.assign({
|
|
||||||
strict: (process.env.NODE_ENV !== 'production')
|
|
||||||
}, store))
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeRoot (moduleData, id) {
|
|
||||||
moduleData = moduleData.default || moduleData
|
|
||||||
if (moduleData.commit) {
|
|
||||||
throw new Error(\`[nuxt] \${id} should export a method that returns a Vuex instance.\`)
|
|
||||||
}
|
|
||||||
if (typeof moduleData !== 'function') {
|
|
||||||
// Avoid TypeError: setting a property that has only a getter when overwriting top level keys
|
|
||||||
moduleData = { ...moduleData }
|
|
||||||
}
|
|
||||||
moduleData.modules = moduleData.modules || {}
|
|
||||||
return moduleData
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveStoreModules (store, moduleData, id) {
|
|
||||||
moduleData = moduleData.default || moduleData
|
|
||||||
|
|
||||||
const namespaces = id.split('/').filter(Boolean)
|
|
||||||
let moduleName = namespaces[namespaces.length - 1]
|
|
||||||
|
|
||||||
// If src is a known Vuex property
|
|
||||||
if (VUEX_PROPERTIES.includes(moduleName)) {
|
|
||||||
const property = moduleName
|
|
||||||
const propertyStoreModule = getStoreModule(store, namespaces, { isProperty: true })
|
|
||||||
// Replace state since it's a function
|
|
||||||
mergeProperty(propertyStoreModule, moduleData, property)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const storeModule = getStoreModule(store, namespaces)
|
|
||||||
|
|
||||||
for (const property of VUEX_PROPERTIES) {
|
|
||||||
mergeProperty(storeModule, moduleData[property], property)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleData.namespaced === false) {
|
|
||||||
delete storeModule.namespaced
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getStoreModule (storeModule, namespaces, { isProperty = false } = {}) {
|
|
||||||
// If ./mutations.js
|
|
||||||
if (!namespaces.length || (isProperty && namespaces.length === 1)) {
|
|
||||||
return storeModule
|
|
||||||
}
|
|
||||||
|
|
||||||
const namespace = namespaces.shift()
|
|
||||||
|
|
||||||
storeModule.modules[namespace] = storeModule.modules[namespace] || {}
|
|
||||||
storeModule.modules[namespace].namespaced = true
|
|
||||||
storeModule.modules[namespace].modules = storeModule.modules[namespace].modules || {}
|
|
||||||
|
|
||||||
return getStoreModule(storeModule.modules[namespace], namespaces, { isProperty })
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeProperty (storeModule, moduleData, property) {
|
|
||||||
if (!moduleData) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (property === 'state') {
|
|
||||||
storeModule.state = moduleData || storeModule.state
|
|
||||||
} else {
|
|
||||||
storeModule[property] = { ...storeModule[property], ...moduleData }
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import type { InlineConfig, SSROptions } from 'vite'
|
|
||||||
import type { VueViteOptions } from 'vite-plugin-vue2'
|
|
||||||
|
|
||||||
export interface Nuxt {
|
|
||||||
options: any;
|
|
||||||
resolver: any;
|
|
||||||
hook: Function;
|
|
||||||
callHook: Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ViteOptions extends Omit<InlineConfig, 'build'> {
|
|
||||||
/**
|
|
||||||
* Options for vite-plugin-vue2
|
|
||||||
*
|
|
||||||
* @see https://github.com/underfin/vite-plugin-vue2
|
|
||||||
*/
|
|
||||||
vue?: VueViteOptions
|
|
||||||
|
|
||||||
ssr?: boolean | SSROptions
|
|
||||||
|
|
||||||
build?: boolean | InlineConfig['build']
|
|
||||||
|
|
||||||
experimentWarning?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ViteBuildContext {
|
|
||||||
nuxt: Nuxt;
|
|
||||||
builder: {
|
|
||||||
plugins: { name: string; mode?: 'client' | 'server'; src: string; }[];
|
|
||||||
};
|
|
||||||
config: ViteOptions;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import { promises as fsp, readdirSync, statSync } from 'fs'
|
|
||||||
import { join } from 'pathe'
|
|
||||||
|
|
||||||
export function readDirRecursively (dir: string) {
|
|
||||||
return readdirSync(dir).reduce((files, file) => {
|
|
||||||
const name = join(dir, file)
|
|
||||||
const isDirectory = statSync(name).isDirectory()
|
|
||||||
return isDirectory ? [...files, ...readDirRecursively(name)] : [...files, name]
|
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function isDirectory (path: string) {
|
|
||||||
try {
|
|
||||||
return (await fsp.stat(path)).isDirectory()
|
|
||||||
} catch (_err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import { join } from 'pathe'
|
|
||||||
import fsExtra from 'fs-extra'
|
|
||||||
|
|
||||||
export const wpfs = {
|
|
||||||
...fsExtra,
|
|
||||||
join
|
|
||||||
} as any
|
|
@ -1,157 +0,0 @@
|
|||||||
import { resolve } from 'pathe'
|
|
||||||
import * as vite from 'vite'
|
|
||||||
import { isIgnored, logger } from '@nuxt/kit'
|
|
||||||
import { sanitizeFilePath } from 'mlly'
|
|
||||||
import { getPort } from 'get-port-please'
|
|
||||||
import { joinURL, withoutLeadingSlash } from 'ufo'
|
|
||||||
import { distDir } from '../dirs'
|
|
||||||
import { warmupViteServer } from '../../../vite/src/utils/warmup'
|
|
||||||
import { DynamicBasePlugin } from '../../../vite/src/plugins/dynamic-base'
|
|
||||||
import { buildClient } from './client'
|
|
||||||
import { buildServer } from './server'
|
|
||||||
import { defaultExportPlugin } from './plugins/default-export'
|
|
||||||
import { jsxPlugin } from './plugins/jsx'
|
|
||||||
import { replace } from './plugins/replace'
|
|
||||||
import { resolveCSSOptions } from './css'
|
|
||||||
import type { Nuxt, ViteBuildContext, ViteOptions } from './types'
|
|
||||||
import { prepareManifests } from './manifest'
|
|
||||||
|
|
||||||
async function bundle (nuxt: Nuxt, builder: any) {
|
|
||||||
for (const p of builder.plugins) {
|
|
||||||
p.src = nuxt.resolver.resolvePath(resolve(nuxt.options.buildDir, p.src))
|
|
||||||
}
|
|
||||||
|
|
||||||
const hmrPortDefault = 24678 // Vite's default HMR port
|
|
||||||
const hmrPort = await getPort({
|
|
||||||
port: hmrPortDefault,
|
|
||||||
ports: Array.from({ length: 20 }, (_, i) => hmrPortDefault + 1 + i)
|
|
||||||
})
|
|
||||||
|
|
||||||
const ctx: ViteBuildContext = {
|
|
||||||
nuxt,
|
|
||||||
builder,
|
|
||||||
config: vite.mergeConfig(
|
|
||||||
{
|
|
||||||
// defaults from packages/schema/src/config/vite
|
|
||||||
root: nuxt.options.srcDir,
|
|
||||||
mode: nuxt.options.dev ? 'development' : 'production',
|
|
||||||
logLevel: 'warn',
|
|
||||||
base: nuxt.options.dev
|
|
||||||
? joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir)
|
|
||||||
: '/__NUXT_BASE__/',
|
|
||||||
publicDir: resolve(nuxt.options.rootDir, nuxt.options.srcDir, nuxt.options.dir.static),
|
|
||||||
vue: {
|
|
||||||
isProduction: !nuxt.options.dev,
|
|
||||||
template: {
|
|
||||||
compilerOptions: nuxt.options.vue.compilerOptions
|
|
||||||
}
|
|
||||||
},
|
|
||||||
esbuild: {
|
|
||||||
jsxFactory: 'h',
|
|
||||||
jsxFragment: 'Fragment',
|
|
||||||
tsconfigRaw: '{}'
|
|
||||||
},
|
|
||||||
clearScreen: false,
|
|
||||||
define: {
|
|
||||||
'process.dev': nuxt.options.dev,
|
|
||||||
'process.static': nuxt.options.target === 'static',
|
|
||||||
'process.env.NODE_ENV': JSON.stringify(nuxt.options.dev ? 'development' : 'production'),
|
|
||||||
'process.mode': JSON.stringify(nuxt.options.dev ? 'development' : 'production'),
|
|
||||||
'process.target': JSON.stringify(nuxt.options.target)
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
|
|
||||||
alias: {
|
|
||||||
...nuxt.options.alias,
|
|
||||||
'#build': nuxt.options.buildDir,
|
|
||||||
'.nuxt': nuxt.options.buildDir,
|
|
||||||
'/entry.mjs': resolve(nuxt.options.buildDir, 'client.js'),
|
|
||||||
'web-streams-polyfill/ponyfill/es2018': resolve(distDir, 'runtime/vite/mock/web-streams-polyfill.mjs'),
|
|
||||||
'whatwg-url': resolve(distDir, 'runtime/vite/mock/whatwg-url.mjs'),
|
|
||||||
// Cannot destructure property 'AbortController' of ..
|
|
||||||
'abort-controller': resolve(distDir, 'runtime/vite/mock/abort-controller.mjs')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
optimizeDeps: {
|
|
||||||
exclude: [
|
|
||||||
...nuxt.options.build.transpile.filter(i => typeof i === 'string'),
|
|
||||||
'vue-demi',
|
|
||||||
'ufo',
|
|
||||||
'date-fns',
|
|
||||||
'nanoid',
|
|
||||||
'vue'
|
|
||||||
// TODO(Anthony): waiting for Vite's fix https://github.com/vitejs/vite/issues/5688
|
|
||||||
// ...nuxt.options.build.transpile.filter(i => typeof i === 'string'),
|
|
||||||
// 'vue-demi'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
css: resolveCSSOptions(nuxt),
|
|
||||||
build: {
|
|
||||||
assetsDir: nuxt.options.dev ? withoutLeadingSlash(nuxt.options.app.buildAssetsDir) : '.',
|
|
||||||
emptyOutDir: false,
|
|
||||||
rollupOptions: {
|
|
||||||
output: { sanitizeFileName: sanitizeFilePath }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
replace({
|
|
||||||
__webpack_public_path__: 'globalThis.__webpack_public_path__'
|
|
||||||
}),
|
|
||||||
jsxPlugin(),
|
|
||||||
DynamicBasePlugin.vite(),
|
|
||||||
defaultExportPlugin()
|
|
||||||
],
|
|
||||||
server: {
|
|
||||||
watch: {
|
|
||||||
ignored: isIgnored
|
|
||||||
},
|
|
||||||
hmr: {
|
|
||||||
// https://github.com/nuxt/framework/issues/4191
|
|
||||||
protocol: 'ws',
|
|
||||||
clientPort: hmrPort,
|
|
||||||
port: hmrPort
|
|
||||||
},
|
|
||||||
fs: {
|
|
||||||
strict: false,
|
|
||||||
allow: [
|
|
||||||
nuxt.options.buildDir,
|
|
||||||
nuxt.options.srcDir,
|
|
||||||
nuxt.options.rootDir,
|
|
||||||
...nuxt.options.modulesDir
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} as ViteOptions,
|
|
||||||
nuxt.options.vite
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
await ctx.nuxt.callHook('vite:extend', ctx)
|
|
||||||
|
|
||||||
if (nuxt.options.dev) {
|
|
||||||
ctx.nuxt.hook('vite:serverCreated', (server: vite.ViteDevServer) => {
|
|
||||||
const start = Date.now()
|
|
||||||
warmupViteServer(server, ['/.nuxt/entry.mjs']).then(() => {
|
|
||||||
logger.info(`Vite warmed up in ${Date.now() - start}ms`)
|
|
||||||
}).catch(logger.error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
await buildClient(ctx)
|
|
||||||
await prepareManifests(ctx)
|
|
||||||
await buildServer(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ViteBuilder {
|
|
||||||
builder: any
|
|
||||||
nuxt: Nuxt
|
|
||||||
|
|
||||||
constructor (builder: any) {
|
|
||||||
this.builder = builder
|
|
||||||
this.nuxt = builder.nuxt
|
|
||||||
}
|
|
||||||
|
|
||||||
build () {
|
|
||||||
return bundle(this.nuxt, this.builder)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
import { pathToFileURL } from 'url'
|
|
||||||
import MagicString from 'magic-string'
|
|
||||||
import { findStaticImports } from 'mlly'
|
|
||||||
import { parseQuery, parseURL } from 'ufo'
|
|
||||||
import { createUnplugin } from 'unplugin'
|
|
||||||
|
|
||||||
export const VueCompat = createUnplugin((opts: { src?: string }) => {
|
|
||||||
return {
|
|
||||||
name: 'nuxt-legacy-vue-transform',
|
|
||||||
enforce: 'post',
|
|
||||||
transformInclude (id) {
|
|
||||||
if (id.includes('vue2-bridge')) { return false }
|
|
||||||
|
|
||||||
const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href))
|
|
||||||
const query = parseQuery(search)
|
|
||||||
|
|
||||||
// vue files
|
|
||||||
if (pathname.endsWith('.vue') && (query.type === 'script' || !search)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// js files
|
|
||||||
if (pathname.match(/\.((c|m)?j|t)sx?/g)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
transform (code, id) {
|
|
||||||
if (id.includes('vue2-bridge')) { return }
|
|
||||||
|
|
||||||
const s = new MagicString(code)
|
|
||||||
const imports = findStaticImports(code).filter(i => i.type === 'static' && vueAliases.includes(i.specifier))
|
|
||||||
|
|
||||||
for (const i of imports) {
|
|
||||||
s.overwrite(i.start, i.end, i.code.replace(`"${i.specifier}"`, `"${opts.src}"`).replace(`'${i.specifier}'`, `'${opts.src}'`))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.hasChanged()) {
|
|
||||||
return {
|
|
||||||
code: s.toString(),
|
|
||||||
map: s.generateMap({ source: id, includeContent: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const vueAliases = [
|
|
||||||
// vue
|
|
||||||
'vue',
|
|
||||||
// vue 3 helper packages
|
|
||||||
'@vue/shared',
|
|
||||||
'@vue/reactivity',
|
|
||||||
'@vue/runtime-core',
|
|
||||||
'@vue/runtime-dom',
|
|
||||||
// vue-demi
|
|
||||||
'vue-demi',
|
|
||||||
...[
|
|
||||||
// vue 2 dist files
|
|
||||||
'vue/dist/vue.common.dev',
|
|
||||||
'vue/dist/vue.common',
|
|
||||||
'vue/dist/vue.common.prod',
|
|
||||||
'vue/dist/vue.esm.browser',
|
|
||||||
'vue/dist/vue.esm.browser.min',
|
|
||||||
'vue/dist/vue.esm',
|
|
||||||
'vue/dist/vue',
|
|
||||||
'vue/dist/vue.min',
|
|
||||||
'vue/dist/vue.runtime.common.dev',
|
|
||||||
'vue/dist/vue.runtime.common',
|
|
||||||
'vue/dist/vue.runtime.common.prod',
|
|
||||||
'vue/dist/vue.runtime.esm',
|
|
||||||
'vue/dist/vue.runtime',
|
|
||||||
'vue/dist/vue.runtime.min'
|
|
||||||
].flatMap(m => [m, `${m}.js`])
|
|
||||||
]
|
|
36
packages/bridge/types.d.ts
vendored
36
packages/bridge/types.d.ts
vendored
@ -1,36 +0,0 @@
|
|||||||
/// <reference types="nitropack" />
|
|
||||||
import type { NuxtConfig as _NuxtConfig } from '@nuxt/schema'
|
|
||||||
import type { MetaInfo } from 'vue-meta'
|
|
||||||
import type { PluginOptions as ScriptSetupPluginOptions } from 'unplugin-vue2-script-setup/dist'
|
|
||||||
|
|
||||||
export type ScriptSetupOptions = ScriptSetupPluginOptions
|
|
||||||
|
|
||||||
export interface BridgeConfig {
|
|
||||||
nitro: boolean
|
|
||||||
vite: boolean
|
|
||||||
app: boolean | {}
|
|
||||||
capi: boolean | {
|
|
||||||
legacy?: boolean
|
|
||||||
}
|
|
||||||
scriptSetup: boolean | ScriptSetupOptions
|
|
||||||
autoImports: boolean
|
|
||||||
transpile: boolean
|
|
||||||
compatibility: boolean
|
|
||||||
postcss8: boolean
|
|
||||||
resolve: boolean
|
|
||||||
typescript: boolean
|
|
||||||
meta: boolean | null
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Also inherit from @nuxt/types.NuxtConfig for legacy type compat
|
|
||||||
export interface NuxtConfig extends _NuxtConfig {
|
|
||||||
head?: _NuxtConfig['head'] | MetaInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@nuxt/schema' {
|
|
||||||
interface NuxtConfig {
|
|
||||||
bridge?: Partial<BridgeConfig> | false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export declare function defineNuxtConfig(config: NuxtConfig): NuxtConfig
|
|
@ -2,13 +2,6 @@
|
|||||||
"extends": [
|
"extends": [
|
||||||
"@nuxtjs"
|
"@nuxtjs"
|
||||||
],
|
],
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"matchPaths": ["**/bridge/**"],
|
|
||||||
"matchPackageNames": ["vue", "vue-router"],
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ignoreDeps": [
|
"ignoreDeps": [
|
||||||
"docus",
|
"docus",
|
||||||
"@docus/app",
|
"@docus/app",
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
import { fileURLToPath } from 'url'
|
|
||||||
import { describe, expect, it } from 'vitest'
|
|
||||||
import { setup, $fetch, fetch, startServer } from '@nuxt/test-utils'
|
|
||||||
|
|
||||||
// Moving to nuxt/bridge soon
|
|
||||||
describe.skip('fixtures:bridge', async () => {
|
|
||||||
await setup({
|
|
||||||
rootDir: fileURLToPath(new URL('./fixtures/bridge', import.meta.url)),
|
|
||||||
server: true
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('pages', () => {
|
|
||||||
it('render hello world', async () => {
|
|
||||||
expect(await $fetch('/')).to.contain('Hello Vue 2!')
|
|
||||||
})
|
|
||||||
it('uses server Vue build', async () => {
|
|
||||||
expect(await $fetch('/')).to.contain('Rendered on server: true')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('navigate', () => {
|
|
||||||
it('should redirect to index with navigateTo', async () => {
|
|
||||||
const html = await $fetch('/navigate-to/')
|
|
||||||
expect(html).toContain('Hello Vue 2!')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('errors', () => {
|
|
||||||
it('should render a JSON error page', async () => {
|
|
||||||
const res = await fetch('/error', {
|
|
||||||
headers: {
|
|
||||||
accept: 'application/json'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(res.status).toBe(500)
|
|
||||||
const error = await res.json()
|
|
||||||
delete error.stack
|
|
||||||
expect(error).toMatchObject({
|
|
||||||
description: process.env.NUXT_TEST_DEV ? expect.stringContaining('<pre>') : '',
|
|
||||||
message: 'This is a custom error',
|
|
||||||
statusCode: 500,
|
|
||||||
statusMessage: 'Internal Server Error',
|
|
||||||
url: '/error'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render a HTML error page', async () => {
|
|
||||||
const res = await fetch('/error')
|
|
||||||
expect(await res.text()).toContain('This is a custom error')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('dynamic paths', () => {
|
|
||||||
if (process.env.NUXT_TEST_DEV) {
|
|
||||||
// TODO:
|
|
||||||
it.todo('dynamic paths in dev')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (process.env.TEST_WITH_WEBPACK) {
|
|
||||||
// TODO:
|
|
||||||
it.todo('work with webpack')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
it('should work with no overrides', async () => {
|
|
||||||
const html = await $fetch('/assets')
|
|
||||||
for (const match of html.matchAll(/(href|src)="(.*?)"/g)) {
|
|
||||||
const url = match[2]
|
|
||||||
expect(url.startsWith('/_nuxt/') || url === '/public.svg').toBeTruthy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds relative paths to CSS', async () => {
|
|
||||||
const html = 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))
|
|
||||||
const css = await $fetch(cssURL)
|
|
||||||
const imageUrls = Array.from(css.matchAll(/url\(([^)]*)\)/g)).map(m => m[1].replace(/[-.][\w]{8}\./g, '.'))
|
|
||||||
expect(imageUrls).toMatchInlineSnapshot(`
|
|
||||||
[
|
|
||||||
"./logo.svg",
|
|
||||||
"../public.svg",
|
|
||||||
]
|
|
||||||
`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should allow setting base URL and build assets directory', async () => {
|
|
||||||
process.env.NUXT_APP_BUILD_ASSETS_DIR = '/_other/'
|
|
||||||
process.env.NUXT_APP_BASE_URL = '/foo/'
|
|
||||||
await startServer()
|
|
||||||
|
|
||||||
const html = await $fetch('/foo/assets')
|
|
||||||
for (const match of html.matchAll(/(href|src)="(.*?)"/g)) {
|
|
||||||
const url = match[2]
|
|
||||||
// TODO: should be /foo/public.svg
|
|
||||||
expect(url.startsWith('/foo/_other/') || url === '/public.svg').toBeTruthy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should allow setting CDN URL', async () => {
|
|
||||||
process.env.NUXT_APP_BASE_URL = '/foo/'
|
|
||||||
process.env.NUXT_APP_CDN_URL = 'https://example.com/'
|
|
||||||
process.env.NUXT_APP_BUILD_ASSETS_DIR = '/_cdn/'
|
|
||||||
await startServer()
|
|
||||||
|
|
||||||
const html = await $fetch('/foo/assets')
|
|
||||||
for (const match of html.matchAll(/(href|src)="(.*?)"/g)) {
|
|
||||||
const url = match[2]
|
|
||||||
// TODO: should be https://example.com/public.svg
|
|
||||||
expect(url.startsWith('https://example.com/_cdn/') || url === '/public.svg').toBeTruthy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
18
test/fixtures/bridge/assets/logo.svg
vendored
18
test/fixtures/bridge/assets/logo.svg
vendored
@ -1,18 +0,0 @@
|
|||||||
<svg viewBox="0 0 221 65" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-8">
|
|
||||||
<g clip-path="url(#a)">
|
|
||||||
<path fill="currentColor"
|
|
||||||
d="M82.5623 18.5705h7.3017l15.474 24.7415V18.5705h6.741v35.0576h-7.252L89.3025 28.938v24.6901h-6.7402V18.5705ZM142.207 53.628h-6.282v-3.916c-1.429 2.7559-4.339 4.3076-8.015 4.3076-5.822 0-9.603-4.1069-9.603-10.0175V28.3847h6.282v14.3251c0 3.4558 2.146 5.8592 5.362 5.8592 3.524 0 5.974-2.7044 5.974-6.4099V28.3847h6.282V53.628ZM164.064 53.2289l-6.026-8.4144-6.027 8.4144h-6.69l9.296-13.1723-8.58-12.0709h6.843l5.158 7.2641 5.106-7.2641h6.895l-8.632 12.0709 9.295 13.1723h-6.638ZM183.469 20.7726v7.6116h7.149v5.1593h-7.149v12.5311c0 .4208.17.8245.473 1.1223.303.2978.715.4654 1.144.4661h5.532v5.9547h-4.137c-5.617 0-9.293-3.2062-9.293-8.8109V33.5484h-5.056v-5.1642h3.172c1.479 0 2.34-.8639 2.34-2.2932v-5.3184h5.825Z">
|
|
||||||
</path>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
||||||
d="M30.1185 11.5456c-1.8853-3.24168-6.5987-3.24169-8.484 0L1.08737 46.8747c-1.885324 3.2417.47133 7.2938 4.24199 7.2938H21.3695c-1.6112-1.4081-2.2079-3.8441-.9886-5.9341l15.5615-26.675-5.8239-10.0138Z"
|
|
||||||
fill="#80EEC0"></path>
|
|
||||||
<path
|
|
||||||
d="M43.1374 19.2952c1.5603-2.6523 5.461-2.6523 7.0212 0l17.0045 28.9057c1.5603 2.6522-.39 5.9676-3.5106 5.9676h-34.009c-3.1206 0-5.0709-3.3154-3.5106-5.9676l17.0045-28.9057ZM209.174 53.8005H198.483c0-1.8514.067-3.4526 0-6.0213h10.641c1.868 0 3.353.1001 4.354-.934 1-1.0341 1.501-2.3351 1.501-3.9029 0-1.8347-.667-3.2191-2.002-4.1532-1.301-.9674-2.985-1.4511-5.054-1.4511h-2.601v-5.2539h2.652c1.701 0 3.119-.4003 4.253-1.2009 1.134-.8006 1.701-1.9849 1.701-3.5527 0-1.301-.434-2.3351-1.301-3.1023-.834-.8007-2.001-1.201-3.503-1.201-1.634 0-2.918.4837-3.853 1.4511-.9.9674-1.401 2.1517-1.501 3.5527h-6.254c.133-3.2358 1.251-5.7877 3.352-7.6558 2.135-1.868 4.887-2.8021 8.256-2.8021 2.402 0 4.42.4337 6.055 1.301 1.668.834 2.919 1.9515 3.753 3.3525.867 1.4011 1.301 2.9523 1.301 4.6536 0 1.9681-.551 3.636-1.651 5.0037-1.068 1.3344-2.402 2.235-4.004 2.7021 1.969.4003 3.57 1.3677 4.804 2.9022 1.234 1.5011 1.852 3.4025 1.852 5.7043 0 1.9347-.468 3.7028-1.402 5.304-.934 1.6012-2.301 2.8855-4.103 3.8529-1.768.9674-3.953 1.4511-6.555 1.4511Z"
|
|
||||||
fill="#00DC82"></path>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id="a">
|
|
||||||
<path fill="#fff" d="M0 0h221v65H0z"></path>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.3 KiB |
20
test/fixtures/bridge/components/FetchTest.vue
vendored
20
test/fixtures/bridge/components/FetchTest.vue
vendored
@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<tr><td><b>useFetch</b></td><td> {{ fetched }}</td></tr>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, ref, useFetch } from '@nuxtjs/composition-api'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup () {
|
|
||||||
const fetched = ref('🚧')
|
|
||||||
useFetch(() => {
|
|
||||||
fetched.value = '✅'
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
fetched
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
16
test/fixtures/bridge/layouts/default.vue
vendored
16
test/fixtures/bridge/layouts/default.vue
vendored
@ -1,16 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<Nuxt />
|
|
||||||
<hr>
|
|
||||||
Route: {{ route.path }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
setup () {
|
|
||||||
const route = useRoute()
|
|
||||||
return { route }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
11
test/fixtures/bridge/layouts/error.vue
vendored
11
test/fixtures/bridge/layouts/error.vue
vendored
@ -1,11 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
{{ error.message || 'An error occurred' }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: ['error']
|
|
||||||
}
|
|
||||||
</script>
|
|
25
test/fixtures/bridge/nuxt.config.ts
vendored
25
test/fixtures/bridge/nuxt.config.ts
vendored
@ -1,25 +0,0 @@
|
|||||||
import { defineNuxtConfig } from '@nuxt/bridge'
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
global.__NUXT_PREPATHS__ = (global.__NUXT_PREPATHS__ || []).concat(__dirname)
|
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
components: true,
|
|
||||||
serverMiddleware: [
|
|
||||||
{
|
|
||||||
handle (req, _res, next) {
|
|
||||||
req.spa = req.url.includes('?spa')
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
buildDir: process.env.NITRO_BUILD_DIR,
|
|
||||||
plugins: ['~/plugins/setup.js'],
|
|
||||||
nitro: {
|
|
||||||
output: { dir: process.env.NITRO_OUTPUT_DIR }
|
|
||||||
},
|
|
||||||
bridge: {
|
|
||||||
meta: true,
|
|
||||||
vite: !process.env.TEST_WITH_WEBPACK
|
|
||||||
}
|
|
||||||
})
|
|
16
test/fixtures/bridge/package.json
vendored
16
test/fixtures/bridge/package.json
vendored
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"private": true,
|
|
||||||
"name": "fixture-basic",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "nuxi dev",
|
|
||||||
"build": "nuxi build"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@nuxt/bridge": "*",
|
|
||||||
"nuxt-edge": "latest",
|
|
||||||
"vue": "^2"
|
|
||||||
},
|
|
||||||
"installConfig": {
|
|
||||||
"hoistingLimits": "workspaces"
|
|
||||||
}
|
|
||||||
}
|
|
20
test/fixtures/bridge/pages/assets.vue
vendored
20
test/fixtures/bridge/pages/assets.vue
vendored
@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<img src="~/assets/logo.svg" class="h-20 mb-4">
|
|
||||||
<img src="/public.svg" class="h-20 mb-4">
|
|
||||||
<img :src="logo" class="h-20 mb-4">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import logo from '~/assets/logo.svg'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#__nuxt {
|
|
||||||
background-image: url('~/assets/logo.svg');
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
background-image: url('/public.svg');
|
|
||||||
}
|
|
||||||
</style>
|
|
7
test/fixtures/bridge/pages/error.vue
vendored
7
test/fixtures/bridge/pages/error.vue
vendored
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
throw new Error('This is a custom error')
|
|
||||||
</script>
|
|
20
test/fixtures/bridge/pages/index.vue
vendored
20
test/fixtures/bridge/pages/index.vue
vendored
@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div>Hello Vue {{ version }}!</div>
|
|
||||||
<div>
|
|
||||||
State: {{ state }} <button @click="updateState">
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
Rendered on server: {{ serverBuild }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
useMeta({ meta: [{ name: 'description', content: 'This is a page to demo Nuxt Bridge.' }] })
|
|
||||||
const version = ref('2')
|
|
||||||
const state = useState('test-state')
|
|
||||||
state.value = '123'
|
|
||||||
const updateState = () => { state.value = '456' }
|
|
||||||
const serverBuild = useState('server-build', () => getCurrentInstance().proxy.$isServer)
|
|
||||||
</script>
|
|
88
test/fixtures/bridge/pages/legacy-capi.vue
vendored
88
test/fixtures/bridge/pages/legacy-capi.vue
vendored
@ -1,88 +0,0 @@
|
|||||||
<template>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<!-- Basic setup function -->
|
|
||||||
<tr><td><b>setup</b></td><td> {{ setup }}</td></tr>
|
|
||||||
<!-- Ref -->
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>ref</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ ref }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button @click="ref = '❇️'">
|
|
||||||
update
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<!-- Lifecycle methods -->
|
|
||||||
<tr><td><b>onMounted</b></td><td> {{ mounted }}</td></tr>
|
|
||||||
<!-- Wrappers -->
|
|
||||||
<tr><td><b>useStore</b></td><td> {{ store.state.test }}</td></tr>
|
|
||||||
<tr><td><b>useRoute</b></td><td> {{ route.path === '/legacy-capi' ? '✅' : '❌' }}</td></tr>
|
|
||||||
<tr><td><b>useContext</b></td><td> {{ Object.keys(context).length ? '✅' : '❌' }}</td></tr>
|
|
||||||
<!-- Helpers -->
|
|
||||||
<tr><td><b>useAsync</b></td><td> {{ async }}</td></tr>
|
|
||||||
<tr><td><b>ssrRef</b></td><td> {{ ssrRef }}</td></tr>
|
|
||||||
<tr><td><b>shallowSsrRef</b></td><td> {{ shallow }}</td></tr>
|
|
||||||
<tr><td><b>ssrPromise</b></td><td> {{ promise }}</td></tr>
|
|
||||||
<tr>
|
|
||||||
<td><b>useMeta</b></td><td> {{ title }}</td>
|
|
||||||
<td>
|
|
||||||
<button @click="title = '❇️'">
|
|
||||||
update
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td><b>onGlobalSetup</b></td><td> {{ globalsetup }}</td></tr>
|
|
||||||
<FetchTest />
|
|
||||||
<tr><td><b>reqSsrRef</b></td><td> {{ '⛔️' }}</td></tr>
|
|
||||||
<tr><td><b>reqRef</b></td><td> {{ '⛔️' }}</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { useRoute, useContext, useStore, useAsync, ssrRef, shallowSsrRef, ssrPromise, useMeta } from '@nuxtjs/composition-api'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup () {
|
|
||||||
const mounted = ref()
|
|
||||||
const shallow = shallowSsrRef('❌')
|
|
||||||
const { isHMR, $globalsetup } = useContext()
|
|
||||||
const { title } = useMeta()
|
|
||||||
if (process.server || isHMR) {
|
|
||||||
shallow.value = '✅'
|
|
||||||
title.value = '❌'
|
|
||||||
}
|
|
||||||
const promise = ref(null)
|
|
||||||
ssrPromise(() => new Promise(resolve => setTimeout(() => resolve(process.server || isHMR ? '✅' : '❌'), 100))).then((r) => {
|
|
||||||
promise.value = r
|
|
||||||
})
|
|
||||||
onMounted(() => {
|
|
||||||
mounted.value = '✅'
|
|
||||||
title.value = '✅'
|
|
||||||
})
|
|
||||||
const store = useStore()
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
return {
|
|
||||||
setup: '✅',
|
|
||||||
ref: ref('✅'),
|
|
||||||
mounted,
|
|
||||||
store,
|
|
||||||
route,
|
|
||||||
context: useContext(),
|
|
||||||
async: useAsync(() => new Promise(resolve => setTimeout(() => resolve(process.server || isHMR ? '✅' : '❌'), 100))),
|
|
||||||
ssrRef: ssrRef(() => process.server || isHMR ? '✅' : '❌'),
|
|
||||||
shallow,
|
|
||||||
promise,
|
|
||||||
title,
|
|
||||||
globalsetup: $globalsetup
|
|
||||||
}
|
|
||||||
},
|
|
||||||
head: {}
|
|
||||||
})
|
|
||||||
</script>
|
|
7
test/fixtures/bridge/pages/navigate-to.vue
vendored
7
test/fixtures/bridge/pages/navigate-to.vue
vendored
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>You should not see me</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
navigateTo('/', { replace: true })
|
|
||||||
</script>
|
|
7
test/fixtures/bridge/pages/test/_slug.vue
vendored
7
test/fixtures/bridge/pages/test/_slug.vue
vendored
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<nuxt-link :to="`/test/${Math.random() * 100}`">
|
|
||||||
Random path
|
|
||||||
</nuxt-link>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
15
test/fixtures/bridge/plugins/setup.js
vendored
15
test/fixtures/bridge/plugins/setup.js
vendored
@ -1,15 +0,0 @@
|
|||||||
import { onGlobalSetup, ref } from '@nuxtjs/composition-api'
|
|
||||||
|
|
||||||
import { defineNuxtPlugin } from '#app'
|
|
||||||
|
|
||||||
export default defineNuxtPlugin(() => {
|
|
||||||
const globalsetup = ref('🚧')
|
|
||||||
onGlobalSetup(() => {
|
|
||||||
globalsetup.value = '✅'
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
provide: {
|
|
||||||
globalsetup
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
1
test/fixtures/bridge/server/api/hello.ts
vendored
1
test/fixtures/bridge/server/api/hello.ts
vendored
@ -1 +0,0 @@
|
|||||||
export default () => 'Hello API'
|
|
4
test/fixtures/bridge/server/api/hey/index.ts
vendored
4
test/fixtures/bridge/server/api/hey/index.ts
vendored
@ -1,4 +0,0 @@
|
|||||||
export default () => ({
|
|
||||||
foo: 'bar',
|
|
||||||
baz: 'qux'
|
|
||||||
})
|
|
18
test/fixtures/bridge/static/public.svg
vendored
18
test/fixtures/bridge/static/public.svg
vendored
@ -1,18 +0,0 @@
|
|||||||
<svg viewBox="0 0 221 65" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-8">
|
|
||||||
<g clip-path="url(#a)">
|
|
||||||
<path fill="currentColor"
|
|
||||||
d="M82.5623 18.5705h7.3017l15.474 24.7415V18.5705h6.741v35.0576h-7.252L89.3025 28.938v24.6901h-6.7402V18.5705ZM142.207 53.628h-6.282v-3.916c-1.429 2.7559-4.339 4.3076-8.015 4.3076-5.822 0-9.603-4.1069-9.603-10.0175V28.3847h6.282v14.3251c0 3.4558 2.146 5.8592 5.362 5.8592 3.524 0 5.974-2.7044 5.974-6.4099V28.3847h6.282V53.628ZM164.064 53.2289l-6.026-8.4144-6.027 8.4144h-6.69l9.296-13.1723-8.58-12.0709h6.843l5.158 7.2641 5.106-7.2641h6.895l-8.632 12.0709 9.295 13.1723h-6.638ZM183.469 20.7726v7.6116h7.149v5.1593h-7.149v12.5311c0 .4208.17.8245.473 1.1223.303.2978.715.4654 1.144.4661h5.532v5.9547h-4.137c-5.617 0-9.293-3.2062-9.293-8.8109V33.5484h-5.056v-5.1642h3.172c1.479 0 2.34-.8639 2.34-2.2932v-5.3184h5.825Z">
|
|
||||||
</path>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
||||||
d="M30.1185 11.5456c-1.8853-3.24168-6.5987-3.24169-8.484 0L1.08737 46.8747c-1.885324 3.2417.47133 7.2938 4.24199 7.2938H21.3695c-1.6112-1.4081-2.2079-3.8441-.9886-5.9341l15.5615-26.675-5.8239-10.0138Z"
|
|
||||||
fill="#80EEC0"></path>
|
|
||||||
<path
|
|
||||||
d="M43.1374 19.2952c1.5603-2.6523 5.461-2.6523 7.0212 0l17.0045 28.9057c1.5603 2.6522-.39 5.9676-3.5106 5.9676h-34.009c-3.1206 0-5.0709-3.3154-3.5106-5.9676l17.0045-28.9057ZM209.174 53.8005H198.483c0-1.8514.067-3.4526 0-6.0213h10.641c1.868 0 3.353.1001 4.354-.934 1-1.0341 1.501-2.3351 1.501-3.9029 0-1.8347-.667-3.2191-2.002-4.1532-1.301-.9674-2.985-1.4511-5.054-1.4511h-2.601v-5.2539h2.652c1.701 0 3.119-.4003 4.253-1.2009 1.134-.8006 1.701-1.9849 1.701-3.5527 0-1.301-.434-2.3351-1.301-3.1023-.834-.8007-2.001-1.201-3.503-1.201-1.634 0-2.918.4837-3.853 1.4511-.9.9674-1.401 2.1517-1.501 3.5527h-6.254c.133-3.2358 1.251-5.7877 3.352-7.6558 2.135-1.868 4.887-2.8021 8.256-2.8021 2.402 0 4.42.4337 6.055 1.301 1.668.834 2.919 1.9515 3.753 3.3525.867 1.4011 1.301 2.9523 1.301 4.6536 0 1.9681-.551 3.636-1.651 5.0037-1.068 1.3344-2.402 2.235-4.004 2.7021 1.969.4003 3.57 1.3677 4.804 2.9022 1.234 1.5011 1.852 3.4025 1.852 5.7043 0 1.9347-.468 3.7028-1.402 5.304-.934 1.6012-2.301 2.8855-4.103 3.8529-1.768.9674-3.953 1.4511-6.555 1.4511Z"
|
|
||||||
fill="#00DC82"></path>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id="a">
|
|
||||||
<path fill="#fff" d="M0 0h221v65H0z"></path>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.3 KiB |
9
test/fixtures/bridge/store/index.js
vendored
9
test/fixtures/bridge/store/index.js
vendored
@ -1,9 +0,0 @@
|
|||||||
export const state = () => ({
|
|
||||||
test: '❌'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const actions = {
|
|
||||||
nuxtServerInit ({ state }) {
|
|
||||||
state.test = '✅'
|
|
||||||
}
|
|
||||||
}
|
|
3
test/fixtures/bridge/tsconfig.json
vendored
3
test/fixtures/bridge/tsconfig.json
vendored
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./.nuxt/tsconfig.json"
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user