提交 300e30e5 编写于 作者: fxy060608's avatar fxy060608

wip: ssr

上级 77bc71c8
const context = (() => {
if (typeof globalThis !== 'undefined') {
return globalThis
} else if (typeof self !== 'undefined') {
return self
} else if (typeof window !== 'undefined') {
return window
} else {
return Function('return this')()
}
})()
// assign defines
const defines = __DEFINES__
Object.keys(defines).forEach((key) => {
const segments = key.split('.')
let target = context
for (let i = 0; i < segments.length; i++) {
const segment = segments[i]
if (i === segments.length - 1) {
target[segment] = defines[key]
} else {
target = target[segment] || (target[segment] = {})
}
}
})
import { renderToString } from '@vue/server-renderer'
let AppInstance
function createApp(App) {
AppInstance = createVueSSRApp(App).use(plugin)
AppInstance.mount = () => {}
return AppInstance
}
export async function render(url, manifest) {
const app = AppInstance
const router = app.router
// set the router to the desired URL before rendering
router.push(url)
await router.isReady()
// passing SSR context object which will be available via useSSRContext()
// @vitejs/plugin-vue injects code into a component's setup() that registers
// itself on ctx.modules. After the render, ctx.modules would contain all the
// components that have been instantiated during this render call.
const ctx = {}
const html = await renderToString(app, ctx)
// the SSR manifest generated by Vite contains module -> chunk/asset mapping
// which we can then use to determine what files need to be preloaded for this
// request.
const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
return [html, preloadLinks]
}
function renderPreloadLinks(modules, manifest) {
let links = ''
const seen = new Set()
modules.forEach((id) => {
const files = manifest[id]
if (files) {
files.forEach((file) => {
if (!seen.has(file)) {
seen.add(file)
links += renderPreloadLink(file)
}
})
}
})
return links
}
function renderPreloadLink(file) {
if (file.endsWith('.js')) {
return '<link rel="modulepreload" crossorigin href="' + file + '">'
} else if (file.endsWith('.css')) {
return '<link rel="stylesheet" href="' + file + '">'
} else {
// TODO
return ''
}
}
......@@ -105,7 +105,7 @@ export function initPlugins(
0,
'pre'
)
addPlugin(plugins, uniMainJsPlugin(options), 1, 'pre')
addPlugin(plugins, uniMainJsPlugin(config, options), 1, 'pre')
addPlugin(plugins, uniPagesJsonPlugin(config, options), 1, 'pre')
addPlugin(plugins, uniManifestJsonPlugin(config, options), 1, 'pre')
......
import path from 'path'
import slash from 'slash'
import { Plugin } from 'vite'
import { Plugin, ResolvedConfig } from 'vite'
import { VitePluginUniResolvedOptions } from '../..'
import { generateSSRRenderCode } from '../../utils'
export function uniMainJsPlugin(options: VitePluginUniResolvedOptions): Plugin {
export function uniMainJsPlugin(
config: ResolvedConfig,
options: VitePluginUniResolvedOptions
): Plugin {
const mainPath = slash(path.resolve(options.inputDir, 'main'))
const mainJsPath = mainPath + '.js'
const mainTsPath = mainPath + '.ts'
const pagesJsonJsPath = slash(path.resolve(options.inputDir, 'pages.json.js'))
const isSSR = config.server.middlewareMode
return {
name: 'vite:uni-main-js',
transform(code, id) {
transform(code, id, ssr) {
if (id === mainJsPath || id === mainTsPath) {
let wrapperCode = `function createApp(rootComponent,rootProps){return createVueApp(rootComponent, rootProps).use(plugin)}`
if (code.includes('createSSRApp')) {
code = code.replace('createSSRApp', 'createVueSSRApp')
wrapperCode = `function createSSRApp(App){return createVueSSRApp(App).use(plugin)}`
if (!isSSR) {
code = createApp(code)
} else {
code = code.replace('createApp', 'createVueApp')
code = ssr ? createSSRServerApp(code) : createSSRClientApp(code)
}
return {
code: `import { plugin } from '@dcloudio/uni-h5';import '${pagesJsonJsPath}';${wrapperCode};${code}`,
code: `import { plugin } from '@dcloudio/uni-h5';import '${pagesJsonJsPath}';${code}`,
map: this.getCombinedSourcemap(),
}
}
},
}
}
function createApp(code: string) {
return `function createApp(rootComponent,rootProps){return createVueApp(rootComponent, rootProps).use(plugin)};${code.replace(
'createApp',
'createVueApp'
)}`
}
function createSSRClientApp(code: string) {
return `function createApp(rootComponent, rootProps) {const app = createVueSSRApp(rootComponent, rootProps).use(plugin);const oldMount = app.mount;app.mount = (selector) => app.router.isReady().then(() => oldMount.call(app, selector));return app;};${code.replace(
'createApp',
'createVueSSRApp'
)}`
}
function createSSRServerApp(code: string) {
return `${generateSSRRenderCode()};${code.replace(
'createApp',
'createVueSSRApp'
)}`
}
export * from './ssr'
export * from './filter'
export * from './features'
export * from './easycom'
......
import path from 'path'
import fs from 'fs-extra'
function serializeDefine(define: Record<string, any>): string {
let res = `{`
for (const key in define) {
......@@ -10,35 +13,14 @@ function serializeDefine(define: Record<string, any>): string {
}
export function generateSSREnvCode(define: Record<string, any>): string {
return envCode.replace('__DEFINES__', serializeDefine(define))
return fs
.readFileSync(path.join(__dirname, '../../lib/ssr/env.js'), 'utf8')
.replace('__DEFINES__', serializeDefine(define))
}
const envCode = `const context = (() => {
if (typeof globalThis !== 'undefined') {
return globalThis;
}
else if (typeof self !== 'undefined') {
return self;
}
else if (typeof window !== 'undefined') {
return window;
}
else {
return Function('return this')();
}
})();
// assign defines
const defines = __DEFINES__;
Object.keys(defines).forEach((key) => {
const segments = key.split('.');
let target = context;
for (let i = 0; i < segments.length; i++) {
const segment = segments[i];
if (i === segments.length - 1) {
target[segment] = defines[key];
}
else {
target = target[segment] || (target[segment] = {});
}
}
});`
export function generateSSRRenderCode() {
return fs.readFileSync(
path.join(__dirname, '../../lib/ssr/render.js'),
'utf8'
)
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册