mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-29 00:52:01 +00:00
perf(nuxt): emit simpler functional ui templates (w/o lodash) (#27091)
This commit is contained in:
parent
a4d0958727
commit
68f4b193be
@ -8,11 +8,11 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm --filter @nuxt/ui-templates prepack && pnpm --filter './packages/[^u]**' prepack",
|
"build": "pnpm --filter './packages/**' prepack",
|
||||||
"build:stub": "pnpm dev:prepare",
|
"build:stub": "pnpm dev:prepare",
|
||||||
"cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'",
|
"cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'",
|
||||||
"dev": "pnpm play",
|
"dev": "pnpm play",
|
||||||
"dev:prepare": "pnpm --filter @nuxt/ui-templates prepack && pnpm --filter './packages/[^u]**' prepack --stub",
|
"dev:prepare": "pnpm --filter './packages/**' prepack --stub",
|
||||||
"lint": "eslint . --cache",
|
"lint": "eslint . --cache",
|
||||||
"lint:fix": "eslint . --cache --fix",
|
"lint:fix": "eslint . --cache --fix",
|
||||||
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md",
|
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
"test:fixtures:webpack": "TEST_BUILDER=webpack pnpm test:fixtures",
|
"test:fixtures:webpack": "TEST_BUILDER=webpack pnpm test:fixtures",
|
||||||
"test:runtime": "vitest -c vitest.nuxt.config.ts",
|
"test:runtime": "vitest -c vitest.nuxt.config.ts",
|
||||||
"test:types": "pnpm --filter './test/fixtures/**' test:types",
|
"test:types": "pnpm --filter './test/fixtures/**' test:types",
|
||||||
"test:unit": "JITI_CACHE=0 vitest run packages/",
|
"test:unit": "vitest run packages/",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs"
|
"typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs"
|
||||||
},
|
},
|
||||||
|
@ -1 +0,0 @@
|
|||||||
../../../../../ui-templates/dist/templates/error-500.d.ts
|
|
@ -1 +0,0 @@
|
|||||||
../../../../../ui-templates/dist/templates/error-500.js
|
|
1
packages/nuxt/src/core/runtime/nitro/error-500.ts
Symbolic link
1
packages/nuxt/src/core/runtime/nitro/error-500.ts
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../ui-templates/dist/templates/error-500.ts
|
@ -1 +0,0 @@
|
|||||||
../../../../../ui-templates/dist/templates/error-dev.d.ts
|
|
@ -1 +0,0 @@
|
|||||||
../../../../../ui-templates/dist/templates/error-dev.js
|
|
1
packages/nuxt/src/core/runtime/nitro/error-dev.ts
Symbolic link
1
packages/nuxt/src/core/runtime/nitro/error-dev.ts
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../ui-templates/dist/templates/error-dev.ts
|
@ -1,9 +1,9 @@
|
|||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
import { readFileSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs'
|
import { readFileSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs'
|
||||||
import { basename, dirname, join, resolve } from 'pathe'
|
import { basename, dirname, join, resolve } from 'pathe'
|
||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
// @ts-expect-error https://github.com/GoogleChromeLabs/critters/pull/151
|
// @ts-expect-error https://github.com/GoogleChromeLabs/critters/pull/151
|
||||||
import Critters from 'critters'
|
import Critters from 'critters'
|
||||||
import { template } from 'lodash-es'
|
|
||||||
import { genObjectFromRawEntries } from 'knitwork'
|
import { genObjectFromRawEntries } from 'knitwork'
|
||||||
import htmlMinifier from 'html-minifier'
|
import htmlMinifier from 'html-minifier'
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
@ -11,18 +11,20 @@ import { camelCase } from 'scule'
|
|||||||
|
|
||||||
import genericMessages from '../templates/messages.json'
|
import genericMessages from '../templates/messages.json'
|
||||||
|
|
||||||
const r = (...path: string[]) => resolve(join(__dirname, '..', ...path))
|
const r = (path: string) => fileURLToPath(new URL(join('..', path), import.meta.url))
|
||||||
|
|
||||||
const replaceAll = (input: string, search: string | RegExp, replace: string) => input.split(search).join(replace)
|
const replaceAll = (input: string, search: string | RegExp, replace: string) => input.split(search).join(replace)
|
||||||
|
|
||||||
export const RenderPlugin = () => {
|
export const RenderPlugin = () => {
|
||||||
|
let outputDir: string
|
||||||
return <Plugin> {
|
return <Plugin> {
|
||||||
name: 'render',
|
name: 'render',
|
||||||
|
configResolved (config) {
|
||||||
|
outputDir = r(config.build.outDir)
|
||||||
|
},
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
async writeBundle () {
|
async writeBundle () {
|
||||||
const distDir = r('dist')
|
const critters = new Critters({ path: outputDir })
|
||||||
const critters = new Critters({ path: distDir })
|
const htmlFiles = await globby(resolve(outputDir, 'templates/**/*.html'), { absolute: true })
|
||||||
const htmlFiles = await globby(r('dist/templates/**/*.html'))
|
|
||||||
|
|
||||||
const templateExports = []
|
const templateExports = []
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ export const RenderPlugin = () => {
|
|||||||
.filter(src => src?.match(/\.svg$/))
|
.filter(src => src?.match(/\.svg$/))
|
||||||
|
|
||||||
for (const src of svgSources) {
|
for (const src of svgSources) {
|
||||||
const svg = readFileSync(r('dist', src), 'utf-8')
|
const svg = readFileSync(join(outputDir, src), 'utf-8')
|
||||||
const base64Source = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
|
const base64Source = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
|
||||||
html = replaceAll(html, src, base64Source)
|
html = replaceAll(html, src, base64Source)
|
||||||
}
|
}
|
||||||
@ -60,7 +62,7 @@ export const RenderPlugin = () => {
|
|||||||
.filter(([_block, src]) => src?.match(/^\/.*\.js$/))
|
.filter(([_block, src]) => src?.match(/^\/.*\.js$/))
|
||||||
|
|
||||||
for (const [scriptBlock, src] of scriptSources) {
|
for (const [scriptBlock, src] of scriptSources) {
|
||||||
let contents = readFileSync(r('dist', src), 'utf-8')
|
let contents = readFileSync(join(outputDir, src), 'utf-8')
|
||||||
contents = replaceAll(contents, '/* empty css */', '').trim()
|
contents = replaceAll(contents, '/* empty css */', '').trim()
|
||||||
html = html.replace(scriptBlock, contents.length ? `<script>${contents}</script>` : '')
|
html = html.replace(scriptBlock, contents.length ? `<script>${contents}</script>` : '')
|
||||||
}
|
}
|
||||||
@ -77,11 +79,22 @@ export const RenderPlugin = () => {
|
|||||||
const messages = JSON.parse(readFileSync(r(`templates/${templateName}/messages.json`), 'utf-8'))
|
const messages = JSON.parse(readFileSync(r(`templates/${templateName}/messages.json`), 'utf-8'))
|
||||||
|
|
||||||
// Serialize into a js function
|
// Serialize into a js function
|
||||||
const jsCode = [
|
const chunks = html.split(/\{{2,3}\s*[^{}]+\s*\}{2,3}/g).map(chunk => JSON.stringify(chunk))
|
||||||
|
let templateString = chunks.shift()
|
||||||
|
for (const expression of html.matchAll(/\{{2,3}(\s*[^{}]+\s*)\}{2,3}/g)) {
|
||||||
|
templateString += ` + (${expression[1].trim()}) + ${chunks.shift()}`
|
||||||
|
}
|
||||||
|
if (chunks.length > 0) {
|
||||||
|
templateString += ' + ' + chunks.join(' + ')
|
||||||
|
}
|
||||||
|
const functionalCode = [
|
||||||
|
`export type DefaultMessages = Record<${Object.keys({ ...genericMessages, ...messages }).map(a => `"${a}"`).join(' | ') || 'string'}, string | boolean | number >`,
|
||||||
`const _messages = ${JSON.stringify({ ...genericMessages, ...messages })}`,
|
`const _messages = ${JSON.stringify({ ...genericMessages, ...messages })}`,
|
||||||
`const _render = ${template(html, { variable: '__var__', interpolate: /{{{?([\s\S]+?)}?}}/g }).toString().replace('__var__', '{ messages }')}`,
|
'export const template = (messages: Partial<DefaultMessages>) => {',
|
||||||
'const _template = (messages) => _render({ messages: { ..._messages, ...messages } })',
|
' messages = { ..._messages, ...messages }',
|
||||||
].join('\n').trim()
|
` return ${templateString}`,
|
||||||
|
'}',
|
||||||
|
].join('\n')
|
||||||
|
|
||||||
const templateContent = html
|
const templateContent = html
|
||||||
.match(/<body.*?>([\s\S]*)<\/body>/)?.[0]
|
.match(/<body.*?>([\s\S]*)<\/body>/)?.[0]
|
||||||
@ -146,20 +159,13 @@ export const RenderPlugin = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Write new template
|
// Write new template
|
||||||
writeFileSync(fileName.replace('/index.html', '.js'), `${jsCode}\nexport const template = _template`)
|
writeFileSync(fileName.replace('/index.html', '.ts'), functionalCode)
|
||||||
writeFileSync(fileName.replace('/index.html', '.vue'), vueCode)
|
writeFileSync(fileName.replace('/index.html', '.vue'), vueCode)
|
||||||
writeFileSync(fileName.replace('/index.html', '.d.ts'), `${types}`)
|
|
||||||
|
|
||||||
// Remove original html file
|
// Remove original html file
|
||||||
unlinkSync(fileName)
|
unlinkSync(fileName)
|
||||||
rmdirSync(dirname(fileName))
|
rmdirSync(dirname(fileName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write an index file with named exports for each template
|
|
||||||
const contents = templateExports.map(exp => `export { template as ${exp.exportName} } from './templates/${exp.templateName}.js'`).join('\n')
|
|
||||||
writeFileSync(r('dist/index.js'), contents, 'utf8')
|
|
||||||
|
|
||||||
writeFileSync(r('dist/index.d.ts'), replaceAll(contents, /\.js/g, ''), 'utf8')
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,12 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"lint": "eslint --ext .ts,.js .",
|
"lint": "eslint --ext .ts,.js .",
|
||||||
"optimize-assets": "npx svgo public/assets/**/*.svg",
|
"optimize-assets": "npx svgo public/assets/**/*.svg",
|
||||||
"prepack": "pnpm build",
|
"postinstall": "pnpm build",
|
||||||
"prerender": "pnpm build && jiti ./lib/prerender",
|
"prerender": "pnpm build && jiti ./lib/prerender",
|
||||||
"test": "pnpm lint && pnpm build"
|
"test": "pnpm lint && pnpm build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/html-minifier": "4.0.5",
|
"@types/html-minifier": "4.0.5",
|
||||||
"@types/lodash-es": "4.17.12",
|
|
||||||
"@unocss/reset": "0.59.4",
|
"@unocss/reset": "0.59.4",
|
||||||
"critters": "0.0.22",
|
"critters": "0.0.22",
|
||||||
"execa": "8.0.1",
|
"execa": "8.0.1",
|
||||||
@ -28,7 +27,6 @@
|
|||||||
"html-minifier": "4.0.0",
|
"html-minifier": "4.0.0",
|
||||||
"jiti": "1.21.0",
|
"jiti": "1.21.0",
|
||||||
"knitwork": "1.1.0",
|
"knitwork": "1.1.0",
|
||||||
"lodash-es": "4.17.21",
|
|
||||||
"pathe": "1.1.2",
|
"pathe": "1.1.2",
|
||||||
"prettier": "3.2.5",
|
"prettier": "3.2.5",
|
||||||
"scule": "1.3.0",
|
"scule": "1.3.0",
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import { beforeAll, describe, expect, it } from 'vitest'
|
import { rm } from 'node:fs/promises'
|
||||||
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||||
import { execaCommand } from 'execa'
|
import { execaCommand } from 'execa'
|
||||||
import { format } from 'prettier'
|
import { format } from 'prettier'
|
||||||
|
|
||||||
const distDir = fileURLToPath(new URL('../dist/templates', import.meta.url))
|
const distDir = fileURLToPath(new URL('../node_modules/.temp/dist/templates', import.meta.url))
|
||||||
|
|
||||||
describe('template', () => {
|
describe('template', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await execaCommand('pnpm build', {
|
await execaCommand('pnpm build', {
|
||||||
cwd: fileURLToPath(new URL('..', import.meta.url)),
|
cwd: fileURLToPath(new URL('..', import.meta.url)),
|
||||||
|
env: {
|
||||||
|
OUTPUT_DIR: './node_modules/.temp/dist',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
afterAll(() => rm(distDir, { force: true, recursive: true }))
|
||||||
|
|
||||||
function formatCss (css: string) {
|
function formatCss (css: string) {
|
||||||
return format(css, {
|
return format(css, {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { resolve } from 'node:path'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { join } from 'node:path'
|
||||||
import { readdirSync } from 'node:fs'
|
import { readdirSync } from 'node:fs'
|
||||||
|
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
@ -7,10 +8,11 @@ import UnoCSS from 'unocss/vite'
|
|||||||
import { DevRenderingPlugin } from './lib/dev'
|
import { DevRenderingPlugin } from './lib/dev'
|
||||||
import { RenderPlugin } from './lib/render'
|
import { RenderPlugin } from './lib/render'
|
||||||
|
|
||||||
const r = (...path: string[]) => resolve(__dirname, ...path)
|
const r = (...path: string[]) => fileURLToPath(new URL(join(...path), import.meta.url))
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
|
outDir: process.env.OUTPUT_DIR || 'dist',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
|
@ -557,9 +557,6 @@ importers:
|
|||||||
'@types/html-minifier':
|
'@types/html-minifier':
|
||||||
specifier: 4.0.5
|
specifier: 4.0.5
|
||||||
version: 4.0.5
|
version: 4.0.5
|
||||||
'@types/lodash-es':
|
|
||||||
specifier: 4.17.12
|
|
||||||
version: 4.17.12
|
|
||||||
'@unocss/reset':
|
'@unocss/reset':
|
||||||
specifier: 0.59.4
|
specifier: 0.59.4
|
||||||
version: 0.59.4
|
version: 0.59.4
|
||||||
@ -581,9 +578,6 @@ importers:
|
|||||||
knitwork:
|
knitwork:
|
||||||
specifier: 1.1.0
|
specifier: 1.1.0
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
lodash-es:
|
|
||||||
specifier: 4.17.21
|
|
||||||
version: 4.17.21
|
|
||||||
pathe:
|
pathe:
|
||||||
specifier: 1.1.2
|
specifier: 1.1.2
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
|
Loading…
Reference in New Issue
Block a user