mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-16 13:48:13 +00:00
feat(kit): support templates with getContents()
for nuxt 2 (#587)
This commit is contained in:
parent
337bd3d2b4
commit
7fdcee3252
@ -13,6 +13,7 @@
|
|||||||
"prepack": "unbuild"
|
"prepack": "unbuild"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.173",
|
||||||
"unbuild": "latest"
|
"unbuild": "latest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -24,6 +25,7 @@
|
|||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"hookable": "^5.0.0",
|
"hookable": "^5.0.0",
|
||||||
"jiti": "^1.12.3",
|
"jiti": "^1.12.3",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"pathe": "^0.2.0",
|
"pathe": "^0.2.0",
|
||||||
"rc9": "^1.2.0",
|
"rc9": "^1.2.0",
|
||||||
"scule": "^0.2.1",
|
"scule": "^0.2.1",
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import { promises as fsp } from 'fs'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { applyDefaults } from 'untyped'
|
import { applyDefaults } from 'untyped'
|
||||||
import { useNuxt, nuxtCtx } from '../nuxt'
|
import { useNuxt, nuxtCtx } from '../nuxt'
|
||||||
import type { Nuxt } from '../types/nuxt'
|
import type { Nuxt, NuxtTemplate } from '../types/nuxt'
|
||||||
import type { NuxtModule, LegacyNuxtModule, ModuleOptions } from '../types/module'
|
import type { NuxtModule, LegacyNuxtModule, ModuleOptions } from '../types/module'
|
||||||
|
import { compileTemplate, isNuxt2, templateUtils } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
||||||
@ -48,6 +50,39 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (input: NuxtMod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isNuxt2()) {
|
||||||
|
// Support virtual templates with getContents() by writing them to .nuxt directory
|
||||||
|
let virtualTemplates: NuxtTemplate[]
|
||||||
|
nuxt.hook('builder:prepared', (_builder, buildOptions) => {
|
||||||
|
virtualTemplates = []
|
||||||
|
buildOptions.templates.forEach((template, index, arr) => {
|
||||||
|
if (!template.getContents) { return }
|
||||||
|
// Remove template from template array to handle it ourselves
|
||||||
|
arr.splice(index, 1)
|
||||||
|
virtualTemplates.push(template)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
nuxt.hook('build:templates', async (templates) => {
|
||||||
|
const context = {
|
||||||
|
nuxt,
|
||||||
|
utils: templateUtils,
|
||||||
|
app: {
|
||||||
|
dir: nuxt.options.srcDir,
|
||||||
|
extensions: nuxt.options.extensions,
|
||||||
|
plugins: nuxt.options.plugins,
|
||||||
|
templates: [
|
||||||
|
...templates.templatesFiles,
|
||||||
|
...virtualTemplates
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for await (const template of virtualTemplates) {
|
||||||
|
const contents = await compileTemplate({ ...template, src: '' }, context)
|
||||||
|
await fsp.writeFile(template.dst, contents)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Call setup
|
// Call setup
|
||||||
return mod.setup.call(null, resolvedOptions, nuxt)
|
return mod.setup.call(null, resolvedOptions, nuxt)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import fs from 'fs'
|
import { existsSync, promises as fsp } from 'fs'
|
||||||
import { basename, parse, resolve } from 'pathe'
|
import { basename, extname, parse, resolve } from 'pathe'
|
||||||
|
import lodashTemplate from 'lodash/template'
|
||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import type { WebpackPluginInstance, Configuration as WebpackConfig } from 'webpack'
|
import type { WebpackPluginInstance, Configuration as WebpackConfig } from 'webpack'
|
||||||
import type { Plugin as VitePlugin, UserConfig as ViteConfig } from 'vite'
|
import type { Plugin as VitePlugin, UserConfig as ViteConfig } from 'vite'
|
||||||
|
import { camelCase } from 'scule'
|
||||||
import { useNuxt } from '../nuxt'
|
import { useNuxt } from '../nuxt'
|
||||||
import type { NuxtTemplate, NuxtPlugin, NuxtPluginTemplate } from '../types/nuxt'
|
import type { NuxtTemplate, NuxtPlugin, NuxtPluginTemplate } from '../types/nuxt'
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ export function normalizeTemplate (template: NuxtTemplate | string): NuxtTemplat
|
|||||||
|
|
||||||
// Use src if provided
|
// Use src if provided
|
||||||
if (template.src) {
|
if (template.src) {
|
||||||
if (!fs.existsSync(template.src)) {
|
if (!existsSync(template.src)) {
|
||||||
throw new Error('Template not found: ' + template.src)
|
throw new Error('Template not found: ' + template.src)
|
||||||
}
|
}
|
||||||
if (!template.filename) {
|
if (!template.filename) {
|
||||||
@ -259,3 +261,42 @@ export function addVitePlugin (plugin: VitePlugin, options?: ExtendViteConfigOpt
|
|||||||
export function isNuxt2 (nuxt?: any) {
|
export function isNuxt2 (nuxt?: any) {
|
||||||
return (nuxt || useNuxt()).version?.startsWith('v2')
|
return (nuxt || useNuxt()).version?.startsWith('v2')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function compileTemplate (template: NuxtTemplate, ctx: any) {
|
||||||
|
const data = { ...ctx, ...template.options }
|
||||||
|
if (template.src) {
|
||||||
|
try {
|
||||||
|
const srcContents = await fsp.readFile(template.src, 'utf-8')
|
||||||
|
return lodashTemplate(srcContents, {})(data)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error compiling template: ', template)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (template.getContents) {
|
||||||
|
return template.getContents(data)
|
||||||
|
}
|
||||||
|
throw new Error('Invalid template: ' + JSON.stringify(template))
|
||||||
|
}
|
||||||
|
|
||||||
|
const serialize = data => JSON.stringify(data, null, 2).replace(/"{(.+)}"/g, '$1')
|
||||||
|
|
||||||
|
const importName = (src: string) => `${camelCase(basename(src, extname(src))).replace(/[^a-zA-Z?\d\s:]/g, '')}_${hash(src)}`
|
||||||
|
|
||||||
|
const importSources = (sources: string | string[], { lazy = false } = {}) => {
|
||||||
|
if (!Array.isArray(sources)) {
|
||||||
|
sources = [sources]
|
||||||
|
}
|
||||||
|
return sources.map((src) => {
|
||||||
|
if (lazy) {
|
||||||
|
return `const ${importName(src)} = () => import('${src}' /* webpackChunkName: '${src}' */)`
|
||||||
|
}
|
||||||
|
return `import ${importName(src)} from '${src}'`
|
||||||
|
}).join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const templateUtils = {
|
||||||
|
serialize,
|
||||||
|
importName,
|
||||||
|
importSources
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import type { HookCallback } from 'hookable'
|
|||||||
import type { Compiler, Configuration, Stats } from 'webpack'
|
import type { Compiler, Configuration, Stats } from 'webpack'
|
||||||
import type { NuxtConfig, NuxtOptions } from '..'
|
import type { NuxtConfig, NuxtOptions } from '..'
|
||||||
import type { ModuleContainer } from '../module/container'
|
import type { ModuleContainer } from '../module/container'
|
||||||
|
import { NuxtTemplate } from '../types/nuxt'
|
||||||
import { Nuxt, NuxtApp } from './nuxt'
|
import { Nuxt, NuxtApp } from './nuxt'
|
||||||
|
|
||||||
type HookResult = Promise<void> | void
|
type HookResult = Promise<void> | void
|
||||||
@ -11,13 +12,6 @@ type Builder = any
|
|||||||
type Generator = any
|
type Generator = any
|
||||||
type Server = any
|
type Server = any
|
||||||
|
|
||||||
type TemplateFile = string | {
|
|
||||||
src?: string
|
|
||||||
dst?: string
|
|
||||||
custom?: boolean
|
|
||||||
options?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
type WatchEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'
|
type WatchEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'
|
||||||
interface PreloadFile {
|
interface PreloadFile {
|
||||||
asType: 'script' | 'style' | 'font'
|
asType: 'script' | 'style' | 'font'
|
||||||
@ -49,7 +43,7 @@ export interface NuxtHooks extends Record<string, HookCallback> {
|
|||||||
'builder:extendPlugins': (plugins: NuxtOptions['plugins']) => HookResult
|
'builder:extendPlugins': (plugins: NuxtOptions['plugins']) => HookResult
|
||||||
'build:templates': (templates: {
|
'build:templates': (templates: {
|
||||||
templateVars: Record<string, any>,
|
templateVars: Record<string, any>,
|
||||||
templatesFiles: TemplateFile[],
|
templatesFiles: NuxtTemplate[],
|
||||||
resolve: (...args: string[]) => string
|
resolve: (...args: string[]) => string
|
||||||
}) => HookResult
|
}) => HookResult
|
||||||
'build:extendRoutes': (routes: any[], resolve: (...args: string[]) => string) => HookResult
|
'build:extendRoutes': (routes: any[], resolve: (...args: string[]) => string) => HookResult
|
||||||
|
@ -23,6 +23,8 @@ export interface Nuxt {
|
|||||||
export interface NuxtTemplate {
|
export interface NuxtTemplate {
|
||||||
/** @deprecated filename */
|
/** @deprecated filename */
|
||||||
fileName?: string
|
fileName?: string
|
||||||
|
/** @deprecated whether template is custom or a nuxt core template */
|
||||||
|
custom?: boolean
|
||||||
/** resolved output file path (generated) */
|
/** resolved output file path (generated) */
|
||||||
dst?: string
|
dst?: string
|
||||||
/** The target filename once the template is copied into the Nuxt buildDir */
|
/** The target filename once the template is copied into the Nuxt buildDir */
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"hookable": "^5.0.0",
|
"hookable": "^5.0.0",
|
||||||
"ignore": "^5.1.8",
|
"ignore": "^5.1.8",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"nuxi": "^0.10.0",
|
"nuxi": "^0.10.0",
|
||||||
"ohmyfetch": "^0.3.1",
|
"ohmyfetch": "^0.3.1",
|
||||||
"pathe": "^0.2.0",
|
"pathe": "^0.2.0",
|
||||||
@ -47,7 +46,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/hash-sum": "^1.0.0",
|
"@types/hash-sum": "^1.0.0",
|
||||||
"@types/lodash": "^4.14.173",
|
|
||||||
"unbuild": "latest",
|
"unbuild": "latest",
|
||||||
"vue-meta": "next"
|
"vue-meta": "next"
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import lodashTemplate from 'lodash/template'
|
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { tryResolvePath, resolveFiles, Nuxt, NuxtApp, NuxtTemplate, normalizePlugin, normalizeTemplate } from '@nuxt/kit'
|
import { tryResolvePath, resolveFiles, Nuxt, NuxtApp, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils } from '@nuxt/kit'
|
||||||
import { readFile, writeFile } from 'fs-extra'
|
import { writeFile } from 'fs-extra'
|
||||||
|
|
||||||
import * as defaultTemplates from '../app/templates'
|
import * as defaultTemplates from '../app/templates'
|
||||||
import * as templateUtils from './template.utils'
|
|
||||||
|
|
||||||
export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp {
|
export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp {
|
||||||
return defu(options, {
|
return defu(options, {
|
||||||
@ -77,20 +75,3 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
|||||||
// Extend app
|
// Extend app
|
||||||
await nuxt.callHook('app:resolve', app)
|
await nuxt.callHook('app:resolve', app)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function compileTemplate (template: NuxtTemplate, ctx: any) {
|
|
||||||
const data = { ...ctx, ...template.options }
|
|
||||||
if (template.src) {
|
|
||||||
try {
|
|
||||||
const srcContents = await readFile(template.src, 'utf-8')
|
|
||||||
return lodashTemplate(srcContents, {})(data)
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error compiling template: ', template)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (template.getContents) {
|
|
||||||
return template.getContents(data)
|
|
||||||
}
|
|
||||||
throw new Error('Invalid template: ' + JSON.stringify(template))
|
|
||||||
}
|
|
||||||
|
@ -1485,6 +1485,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@nuxt/kit@workspace:packages/kit"
|
resolution: "@nuxt/kit@workspace:packages/kit"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@types/lodash": ^4.14.173
|
||||||
consola: ^2.15.3
|
consola: ^2.15.3
|
||||||
create-require: ^1.1.1
|
create-require: ^1.1.1
|
||||||
defu: ^5.0.0
|
defu: ^5.0.0
|
||||||
@ -1493,6 +1494,7 @@ __metadata:
|
|||||||
hash-sum: ^2.0.0
|
hash-sum: ^2.0.0
|
||||||
hookable: ^5.0.0
|
hookable: ^5.0.0
|
||||||
jiti: ^1.12.3
|
jiti: ^1.12.3
|
||||||
|
lodash: ^4.17.21
|
||||||
pathe: ^0.2.0
|
pathe: ^0.2.0
|
||||||
rc9: ^1.2.0
|
rc9: ^1.2.0
|
||||||
scule: ^0.2.1
|
scule: ^0.2.1
|
||||||
@ -10087,7 +10089,6 @@ fsevents@~2.3.2:
|
|||||||
"@nuxt/webpack-builder": ^0.10.0
|
"@nuxt/webpack-builder": ^0.10.0
|
||||||
"@types/fs-extra": ^9.0.13
|
"@types/fs-extra": ^9.0.13
|
||||||
"@types/hash-sum": ^1.0.0
|
"@types/hash-sum": ^1.0.0
|
||||||
"@types/lodash": ^4.14.173
|
|
||||||
"@vue/reactivity": 3.2.16
|
"@vue/reactivity": 3.2.16
|
||||||
"@vue/server-renderer": ^3.2.16
|
"@vue/server-renderer": ^3.2.16
|
||||||
"@vue/shared": 3.2.16
|
"@vue/shared": 3.2.16
|
||||||
@ -10100,7 +10101,6 @@ fsevents@~2.3.2:
|
|||||||
hash-sum: ^2.0.0
|
hash-sum: ^2.0.0
|
||||||
hookable: ^5.0.0
|
hookable: ^5.0.0
|
||||||
ignore: ^5.1.8
|
ignore: ^5.1.8
|
||||||
lodash: ^4.17.21
|
|
||||||
nuxi: ^0.10.0
|
nuxi: ^0.10.0
|
||||||
ohmyfetch: ^0.3.1
|
ohmyfetch: ^0.3.1
|
||||||
pathe: ^0.2.0
|
pathe: ^0.2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user