feat!: generate vue sfcs as part of build (#67)

This commit is contained in:
Daniel Roe 2022-03-10 20:25:58 +00:00 committed by GitHub
parent 1428c46e96
commit 62e2f94fcd
3 changed files with 36 additions and 2 deletions

View File

@ -3,6 +3,7 @@ import { resolve, join, dirname, basename } from 'upath'
import type { Plugin } from 'vite'
import Critters from 'critters'
import template from 'lodash.template'
import { genObjectFromRawEntries } from 'knitwork'
import htmlMinifier from 'html-minifier'
import { camelCase } from 'scule'
import genericMessages from '../templates/messages.json'
@ -72,6 +73,36 @@ export const RenderPlugin = () => {
'const _template = (messages) => _render({ messages: { ..._messages, ...messages } })'
].join('\n').trim()
const templateContent = html
.match(/<body.*?>([\s\S]*)<\/body>/)?.[0]
.replace(/(?<=<|<\/)body/g, 'div')
.replace(/messages\./g, '')
.replace(/<a href="([^"]+)"([^>]*)>([\s\S]*)<\/a>/g, '<NuxtLink to="$1"$2>$3</NuxtLink>')
.replace(/>{{\s*([\s\S]+?)\s*}}<\/[\w-]*>/g, ' v-html="$1" />')
// We are not matching <link> <script> and <meta> tags as these aren't used yet in nuxt/ui
// and should be taken care of wherever this SFC is used
const title = html.match(/<title.*?>([\s\S]*)<\/title>/)?.[1].replace(/{{([\s\S]+?)}}/g, (r) => {
return `\${${r.slice(2, -2)}}`.replace(/messages\./g, 'props.')
})
const styleContent = Array.from(html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/g)).map(block => block[1])
const props = genObjectFromRawEntries(Object.entries({ ...genericMessages, ...messages }).map(([key, value]) => [key, {
type: typeof value === 'string' ? 'String' : typeof value === 'number' ? 'Number' : typeof value === 'boolean' ? 'Boolean' : 'undefined',
default: JSON.stringify(value)
}]))
const vueCode = [
'<script setup lang="ts">',
title && ' import { useMeta } from \'#app\'',
` const props = defineProps(${props})`,
title && ` useMeta({ title: \`${title}\` })`,
'</script>',
'<template>',
templateContent,
'</template>',
'<style scoped>',
...styleContent,
'</style>'
].filter(Boolean).join('\n').trim()
// Generate types
const types = [
`export type DefaultMessages = Record<${Object.keys(messages).map(a => `"${a}"`).join(' | ')}, string | boolean | number >`,
@ -88,6 +119,7 @@ export const RenderPlugin = () => {
// Write new template
await fsp.writeFile(fileName.replace('/index.html', '.mjs'), `${jsCode}\nexport const template = _template`)
await fsp.writeFile(fileName.replace('/index.html', '.vue'), vueCode)
await fsp.writeFile(fileName.replace('/index.html', '.d.ts'), `${types}`)
// Remove original html file

View File

@ -4,7 +4,7 @@
"repository": "nuxt/ui",
"license": "CC-BY-ND-4.0",
"exports": {
"./templates/*": "./dist/templates/*.mjs",
"./templates/*": "./dist/templates/*",
".": "./dist/index.mjs",
"./*": "./dist/*"
},
@ -31,6 +31,7 @@
"globby": "^13.1.1",
"html-minifier": "^4.0.0",
"jiti": "^1.13.0",
"knitwork": "^0.1.1",
"lodash.template": "^4.5.0",
"scule": "^0.2.1",
"upath": "^2.0.1",

View File

@ -1,5 +1,6 @@
{
"statusCode": "500",
"statusMessage": "Server error",
"description": "An error occurred in the application and the page could not be served. If you are the application owner, check your server logs for details."
"description": "An error occurred in the application and the page could not be served. If you are the application owner, check your server logs for details.",
"stack": ""
}