This commit is contained in:
julien huang 2023-12-23 07:14:43 +01:00
parent 4dcc48f4e6
commit 5aac596833
9 changed files with 102 additions and 33 deletions

View File

@ -40,7 +40,7 @@ export default defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
name: { name: {
type: [String, Boolean, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout'], type: [String, Boolean, Object] as unknown as () => unknown extends ['layout'] ? MaybeRef<string | false> : PageMeta['layout'],
default: null default: null
}, },
fallback: { fallback: {

View File

@ -8,7 +8,6 @@ import type { Nuxt, NuxtApp, NuxtPage } from 'nuxt/schema'
import { createRoutesContext } from 'unplugin-vue-router' import { createRoutesContext } from 'unplugin-vue-router'
import { resolveOptions } from 'unplugin-vue-router/options' import { resolveOptions } from 'unplugin-vue-router/options'
import type { EditableTreeNode, Options as TypedRouterOptions } from 'unplugin-vue-router' import type { EditableTreeNode, Options as TypedRouterOptions } from 'unplugin-vue-router'
import type { NitroRouteConfig } from 'nitropack' import type { NitroRouteConfig } from 'nitropack'
import { defu } from 'defu' import { defu } from 'defu'
import { distDir } from '../dirs' import { distDir } from '../dirs'
@ -322,7 +321,8 @@ export default defineNuxtModule({
// Extract macros from pages // Extract macros from pages
const pageMetaOptions: PageMetaPluginOptions = { const pageMetaOptions: PageMetaPluginOptions = {
dev: nuxt.options.dev, dev: nuxt.options.dev,
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
updateTemplates
} }
nuxt.hook('modules:done', () => { nuxt.hook('modules:done', () => {
addVitePlugin(() => PageMetaPlugin.vite(pageMetaOptions)) addVitePlugin(() => PageMetaPlugin.vite(pageMetaOptions))
@ -364,7 +364,18 @@ export default defineNuxtModule({
filename: 'routes.mjs', filename: 'routes.mjs',
getContents ({ app }) { getContents ({ app }) {
const { routes, imports } = normalizeRoutes(app.pages) const { routes, imports } = normalizeRoutes(app.pages)
return [...imports, `export default ${routes}`].join('\n') return `
${
[...imports, `const routes = ${routes}`, `export default routes`].join('\n')
}
if (import.meta.hot) {
import.meta.hot.accept((mod) => {
console.log('up', mod.default)
Object.assign(routes, mod.default)
})
}
`
} }
}) })

View File

@ -8,11 +8,12 @@ import type { Node } from 'estree-walker'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { isAbsolute } from 'pathe' import { isAbsolute } from 'pathe'
import { logger } from '@nuxt/kit' import { logger, updateTemplates as _updateTemplate } from '@nuxt/kit'
import { } from "vite"
export interface PageMetaPluginOptions { export interface PageMetaPluginOptions {
dev?: boolean dev?: boolean
sourcemap?: boolean sourcemap?: boolean
updateTemplates: typeof _updateTemplate
} }
const HAS_MACRO_RE = /\bdefinePageMeta\s*\(\s*/ const HAS_MACRO_RE = /\bdefinePageMeta\s*\(\s*/
@ -26,7 +27,7 @@ const CODE_HMR = `
// Vite // Vite
if (import.meta.hot) { if (import.meta.hot) {
import.meta.hot.accept(mod => { import.meta.hot.accept(mod => {
Object.assign(__nuxt_page_meta, mod) import.meta.hot.invalidate()
}) })
} }
// webpack // webpack
@ -40,15 +41,15 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
return { return {
name: 'nuxt:pages-macros-transform', name: 'nuxt:pages-macros-transform',
enforce: 'post', enforce: 'post',
transformInclude (id) { transformInclude(id) {
return !!parseMacroQuery(id).macro return !!parseMacroQuery(id).macro
}, },
transform (code, id) { transform(code, id) {
const query = parseMacroQuery(id) const query = parseMacroQuery(id)
if (query.type && query.type !== 'script') { return } if (query.type && query.type !== 'script') { return }
const s = new MagicString(code) const s = new MagicString(code)
function result () { function result() {
if (s.hasChanged()) { if (s.hasChanged()) {
return { return {
code: s.toString(), code: s.toString(),
@ -116,7 +117,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
sourceType: 'module', sourceType: 'module',
ecmaVersion: 'latest' ecmaVersion: 'latest'
}) as Node, { }) as Node, {
enter (_node) { enter(_node) {
if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return } if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return }
const node = _node as CallExpression & { start: number, end: number } const node = _node as CallExpression & { start: number, end: number }
const name = 'name' in node.callee && node.callee.name const name = 'name' in node.callee && node.callee.name
@ -126,7 +127,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
let contents = `const __nuxt_page_meta = ${code!.slice(meta.start, meta.end) || 'null'}\nexport default __nuxt_page_meta` + (options.dev ? CODE_HMR : '') let contents = `const __nuxt_page_meta = ${code!.slice(meta.start, meta.end) || 'null'}\nexport default __nuxt_page_meta` + (options.dev ? CODE_HMR : '')
function addImport (name: string | false) { function addImport(name: string | false) {
if (name && importMap.has(name)) { if (name && importMap.has(name)) {
const importValue = importMap.get(name)!.code const importValue = importMap.get(name)!.code
if (!addedImports.has(importValue)) { if (!addedImports.has(importValue)) {
@ -137,7 +138,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
} }
walk(meta, { walk(meta, {
enter (_node) { enter(_node) {
if (_node.type === 'CallExpression') { if (_node.type === 'CallExpression') {
const node = _node as CallExpression & { start: number, end: number } const node = _node as CallExpression & { start: number, end: number }
addImport('name' in node.callee && node.callee.name) addImport('name' in node.callee && node.callee.name)
@ -162,11 +163,22 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
vite: { vite: {
handleHotUpdate: { handleHotUpdate: {
order: 'pre', order: 'pre',
handler: ({ modules }) => { handler: async (ctx) => {
const { modules } = ctx
// Remove macro file from modules list to prevent HMR overrides // Remove macro file from modules list to prevent HMR overrides
const index = modules.findIndex(i => i.id?.includes('?macro=true')) const index = modules.findIndex(i => i.id?.includes('?macro=true'))
if (index !== -1) { if (index !== -1) {
modules.splice(index, 1) const [macroFile] = modules.splice(index, 1)
if (macroFile) {
await console.log(await ctx.read())
debugger
ctx.server.moduleGraph.invalidateModule(macroFile)
ctx.server.reloadModule(macroFile)
// update the macro file
}
} }
} }
} }
@ -176,11 +188,11 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
// https://github.com/vuejs/vue-loader/pull/1911 // https://github.com/vuejs/vue-loader/pull/1911
// https://github.com/vitejs/vite/issues/8473 // https://github.com/vitejs/vite/issues/8473
function rewriteQuery (id: string) { function rewriteQuery(id: string) {
return id.replace(/\?.+$/, r => '?macro=true&' + r.replace(/^\?/, '').replace(/&macro=true/, '')) return id.replace(/\?.+$/, r => '?macro=true&' + r.replace(/^\?/, '').replace(/&macro=true/, ''))
} }
function parseMacroQuery (id: string) { function parseMacroQuery(id: string) {
const { search } = parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id).replace(/\?macro=true$/, '')) const { search } = parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id).replace(/\?macro=true$/, ''))
const query = parseQuery(search) const query = parseQuery(search)
if (id.includes('?macro=true')) { if (id.includes('?macro=true')) {
@ -189,6 +201,6 @@ function parseMacroQuery (id: string) {
return query return query
} }
function getQuotedSpecifier (id: string) { function getQuotedSpecifier(id: string) {
return id.match(/(["']).*\1/)?.[0] return id.match(/(["']).*\1/)?.[0]
} }

View File

@ -91,6 +91,40 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
previousRoute.value = from previousRoute.value = from
}) })
if(import.meta.hot) {
console.log(import.meta.hot)
import.meta.hot.accept( () => {
console.log('hot reload self accept')
})
import.meta.hot.accept( '/pages/index.vue?macro=true', () => {
console.log('hot reload')
})
import.meta.hot.accept( '/pages/index.vue', () => {
console.log('hot reload')
})
import.meta.hot.accept( '/pages/index.vue?macro=true', () => {
console.log('hot reload')
})
import.meta.hot.accept( '#build/routes', () => {
console.log('hot reload')
})
import.meta.hot.accept( '/@id/virtual:nuxt:G:/repo/nuxt/playground/.nuxt/routes.mjs', () => {
console.log('hot reload')
})
import.meta.hot.accept( '/@id/virtual:nuxt:G:/repo/nuxt/playground/.nuxt/routes.mjs', () => {
console.log('hot reload')
})
import.meta.hot.accept("/_nuxt/@id/virtual:nuxt:G:/repo/nuxt/playground/.nuxt/routes.mjs", () => {
console.log('hot reload mod')
})
}
Object.defineProperty(nuxtApp.vueApp.config.globalProperties, 'previousRoute', { Object.defineProperty(nuxtApp.vueApp.config.globalProperties, 'previousRoute', {
get: () => previousRoute.value get: () => previousRoute.value
}) })

View File

@ -1,13 +0,0 @@
<script setup lang="ts">
</script>
<template>
<!-- Edit this file to play around with Nuxt but never commit changes! -->
<div>
Nuxt 3 Playground
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,6 @@
<template>
<div class="blue" style="border: solid blue 1px;">
<slot />
</div>
</template>

View File

@ -0,0 +1,6 @@
<template>
<div class="red">
<slot />
</div>
</template>

View File

@ -0,0 +1,10 @@
<template>
<div>Index Page</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: 'blue',
});
</script>

View File

@ -188,8 +188,11 @@ export default defineNuxtConfig({
compilerOptions: { compilerOptions: {
isCustomElement: (tag) => { isCustomElement: (tag) => {
return tag === 'custom-component' return tag === 'custom-component'
} },
} prefixIdentifiers: false,
},
}, },
experimental: { experimental: {
typedPages: true, typedPages: true,