mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
initial commit
This commit is contained in:
commit
4908a963ca
89
packages/nitro/src/nuxt-deploy.ts
Normal file
89
packages/nitro/src/nuxt-deploy.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { resolve } from 'path'
|
||||
import { rollup, OutputOptions } from 'rollup'
|
||||
import consola from 'consola'
|
||||
import Hookable from 'hookable'
|
||||
import defu from 'defu'
|
||||
import { readFile, writeFile, existsSync } from 'fs-extra'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import gzipSize from 'gzip-size'
|
||||
import chalk from 'chalk'
|
||||
import { getRollupConfig } from './rollup.config'
|
||||
import { tryImport, hl, prettyPath } from './utils'
|
||||
|
||||
async function main () {
|
||||
const rootDir = resolve(process.cwd(), process.argv[2] || '.')
|
||||
|
||||
// Config
|
||||
const config = {
|
||||
rootDir,
|
||||
buildDir: '',
|
||||
targets: [],
|
||||
target: process.argv[3] && process.argv[3][0] !== '-' ? process.argv[3] : null,
|
||||
minify: process.argv.includes('--minify') ? true : null,
|
||||
analyze: process.argv.includes('--analyze') ? true : null,
|
||||
logStartup: true
|
||||
}
|
||||
Object.assign(config, tryImport(rootDir, './nuxt.config')!.deploy)
|
||||
config.buildDir = resolve(config.rootDir, config.buildDir || '.nuxt')
|
||||
|
||||
// Ensure dist exists
|
||||
if (!existsSync(resolve(config.buildDir, 'dist/server'))) {
|
||||
return consola.error('Please use `nuxt build` first to build project!')
|
||||
} else {
|
||||
consola.success('Using existing nuxt build from', prettyPath(config.buildDir))
|
||||
}
|
||||
|
||||
// Compile html template
|
||||
const htmlTemplateFile = resolve(config.buildDir, 'views/app.template.html') // TODO: nuxt3: document.template.html
|
||||
const htmlTemplateFileJS = htmlTemplateFile.replace(/.html$/, '.js').replace('app.', 'document.')
|
||||
const htmlTemplateContents = await readFile(htmlTemplateFile, 'utf-8')
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
const htmlTemplateCompiled = `export default (params) => \`${htmlTemplateContents.replace(/{{ (\w+) }}/g, '${params.$1}')}\``
|
||||
await writeFile(htmlTemplateFileJS, htmlTemplateCompiled)
|
||||
consola.info('Generated', (prettyPath(htmlTemplateFileJS)))
|
||||
|
||||
// Bundle for each target
|
||||
for (let target of config.targets) {
|
||||
if (typeof target === 'string') {
|
||||
target = { target }
|
||||
}
|
||||
|
||||
if (config.target && target.target !== config.target) {
|
||||
continue
|
||||
}
|
||||
|
||||
console.log('\n')
|
||||
consola.info(`Generating bundle for ${hl(target.target)}`)
|
||||
|
||||
const ctx: any = defu(
|
||||
target,
|
||||
config,
|
||||
tryImport(__dirname, `./targets/${target.target}`) || tryImport(config.rootDir, target.target)
|
||||
)
|
||||
|
||||
const hooks = new Hookable()
|
||||
hooks.addHooks(ctx.hooks)
|
||||
|
||||
await hooks.callHook('rollup:prepare', ctx)
|
||||
ctx.rollupConfig = getRollupConfig(ctx)
|
||||
await hooks.callHook('rollup:config', ctx)
|
||||
|
||||
await hooks.callHook('rollup:before', ctx)
|
||||
const build = await rollup(ctx.rollupConfig)
|
||||
await hooks.callHook('rollup:built', ctx, build)
|
||||
|
||||
const { output } = await build.write(ctx.rollupConfig.output as OutputOptions)
|
||||
const size = prettyBytes(output[0].code.length)
|
||||
const zSize = prettyBytes(await gzipSize(output[0].code))
|
||||
consola.success('Generated', prettyPath((ctx.rollupConfig.output as any).file),
|
||||
chalk.gray(`(Size: ${size} Gzip: ${zSize})`)
|
||||
)
|
||||
|
||||
await hooks.callHook('rollup:done', ctx)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
consola.error(err)
|
||||
process.exit(1)
|
||||
})
|
109
packages/nitro/src/rollup.config.ts
Normal file
109
packages/nitro/src/rollup.config.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import Module from 'module'
|
||||
import path from 'path'
|
||||
import { InputOptions, OutputOptions } from 'rollup'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
import commonjs from '@rollup/plugin-commonjs'
|
||||
import resolve from '@rollup/plugin-node-resolve'
|
||||
import alias from '@rollup/plugin-alias'
|
||||
import json from '@rollup/plugin-json'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import analyze from 'rollup-plugin-analyzer'
|
||||
import esbuild from 'rollup-plugin-esbuild'
|
||||
|
||||
export type RollupConfig = InputOptions & { output: OutputOptions }
|
||||
|
||||
export const getRollupConfig = (config) => {
|
||||
const mocks = [
|
||||
'@babel/parser',
|
||||
'@vue/compiler-core',
|
||||
'@vue/compiler-dom',
|
||||
'@vue/compiler-ssr'
|
||||
]
|
||||
|
||||
const extensions = ['.ts', '.mjs', '.js', '.json', '.node']
|
||||
|
||||
const external = []
|
||||
|
||||
if (config.node === false) {
|
||||
mocks.push(...Module.builtinModules)
|
||||
} else {
|
||||
external.push(...Module.builtinModules)
|
||||
}
|
||||
|
||||
const options: RollupConfig = {
|
||||
input: config.entry,
|
||||
|
||||
output: {
|
||||
file: path.resolve(config.buildDir, 'dist/server', `index.${config.target}.js`),
|
||||
format: 'cjs',
|
||||
intro: '',
|
||||
outro: '',
|
||||
preferConst: true
|
||||
},
|
||||
|
||||
external,
|
||||
|
||||
plugins: [
|
||||
replace({
|
||||
values: {
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
}
|
||||
}),
|
||||
|
||||
alias({
|
||||
entries: {
|
||||
'~runtime': path.resolve(__dirname, 'runtime'),
|
||||
'~build': config.buildDir,
|
||||
'~mock': require.resolve('./runtime/mock'),
|
||||
...mocks.reduce((p, c) => ({ ...p, [c]: '~mock' }), {})
|
||||
}
|
||||
}),
|
||||
|
||||
// https://github.com/rollup/plugins/tree/master/packages/node-resolve
|
||||
resolve({
|
||||
extensions,
|
||||
preferBuiltins: true,
|
||||
mainFields: ['main'] // Force resolve CJS (@vue/runtime-core ssrUtils)
|
||||
}),
|
||||
|
||||
// https://github.com/rollup/plugins/tree/master/packages/commonjs
|
||||
commonjs({
|
||||
extensions: extensions.filter(ext => ext !== '.json'),
|
||||
dynamicRequireTargets: ['*.js']
|
||||
}),
|
||||
|
||||
// https://github.com/egoist/rollup-plugin-esbuild
|
||||
esbuild({
|
||||
target: 'node12',
|
||||
include: /\.[jt]s?$/,
|
||||
tsconfig: false,
|
||||
sourceMap: false,
|
||||
loaders: {
|
||||
'.json': 'json',
|
||||
'.js': 'jsx',
|
||||
'.ts': 'ts'
|
||||
}
|
||||
}),
|
||||
|
||||
// https://github.com/rollup/plugins/tree/master/packages/json
|
||||
json()
|
||||
]
|
||||
}
|
||||
|
||||
if (config.logStartup) {
|
||||
options.output.intro += 'global._startTime = process.hrtime();'
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
options.output.outro += 'global._endTime = process.hrtime(global._startTime); global._coldstart = ((_endTime[0] * 1e9) + _endTime[1]) / 1e6; console.log(`λ Cold start took: ${global._coldstart}ms`);'
|
||||
}
|
||||
|
||||
if (config.analyze) {
|
||||
// https://github.com/doesdev/rollup-plugin-analyzer
|
||||
options.plugins.push(analyze())
|
||||
}
|
||||
|
||||
if (config.minify) {
|
||||
options.plugins.push(terser())
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
25
packages/nitro/src/runtime/mock.ts
Normal file
25
packages/nitro/src/runtime/mock.ts
Normal file
@ -0,0 +1,25 @@
|
||||
function getProxy (name) {
|
||||
const fn = function () { }
|
||||
fn.prototype.name = name
|
||||
|
||||
const props = {}
|
||||
|
||||
return new Proxy(fn, {
|
||||
get (_target, prop) {
|
||||
if (prop === 'caller') { return null }
|
||||
return (props[prop] = props[prop] || getProxy(`${name}.${prop.toString()}`))
|
||||
},
|
||||
apply (_target, _this, _args) {
|
||||
console.debug(`${name}(...)`)
|
||||
return getProxy(`${name}()`)
|
||||
},
|
||||
construct (_target, _args, _newT) {
|
||||
return getProxy(`[${name}]`)
|
||||
},
|
||||
enumerate (_target) {
|
||||
return []
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default getProxy('mock')
|
39
packages/nitro/src/runtime/server.ts
Normal file
39
packages/nitro/src/runtime/server.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { createRenderer } from 'vue-bundle-renderer'
|
||||
import devalue from '@nuxt/devalue'
|
||||
|
||||
// @ts-ignore
|
||||
import { renderToString } from './vue2'
|
||||
// @ts-ignore
|
||||
import server from '~build/dist/server/server'
|
||||
// @ts-ignore
|
||||
import clientManifest from '~build/dist/server/client.manifest.json'
|
||||
// @ts-ignore
|
||||
import htmlTemplate from '~build/views/document.template.js'
|
||||
|
||||
const renderer = createRenderer(server, {
|
||||
clientManifest,
|
||||
renderToString
|
||||
})
|
||||
|
||||
export async function render (url) {
|
||||
const ssrContext = {
|
||||
url,
|
||||
runtimeConfig: {
|
||||
public: {},
|
||||
private: {}
|
||||
},
|
||||
_registeredComponents: []
|
||||
}
|
||||
const rendered = await renderer.renderToString(ssrContext)
|
||||
|
||||
const state = `<script>window.__NUXT__ = ${devalue(ssrContext.payload)}</script>`
|
||||
const html = `<div id="__nuxt">${rendered.html}</div>`
|
||||
|
||||
return htmlTemplate({
|
||||
HTML_ATTRS: '',
|
||||
HEAD_ATTRS: '',
|
||||
BODY_ATTRS: '',
|
||||
HEAD: rendered.renderResourceHints() + rendered.renderStyles(),
|
||||
APP: html + state + rendered.renderScripts()
|
||||
})
|
||||
}
|
12
packages/nitro/src/runtime/vue2.ts
Normal file
12
packages/nitro/src/runtime/vue2.ts
Normal file
@ -0,0 +1,12 @@
|
||||
const _renderToString = require('vue-server-renderer/basic.js')
|
||||
|
||||
export function renderToString (component, context) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_renderToString(component, context, (err, result) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(result)
|
||||
})
|
||||
})
|
||||
}
|
2
packages/nitro/src/runtime/vue3.ts
Normal file
2
packages/nitro/src/runtime/vue3.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// @ts-ignore
|
||||
export { renderToString } from '@vue/server-renderer'
|
8
packages/nitro/src/targets/cli/entry.ts
Normal file
8
packages/nitro/src/targets/cli/entry.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { render } from '~runtime/server'
|
||||
|
||||
render(process.argv[2] || '/')
|
||||
.then(html => console.log(html))
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
11
packages/nitro/src/targets/cli/index.ts
Normal file
11
packages/nitro/src/targets/cli/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { relative } from 'path'
|
||||
import consola from 'consola'
|
||||
|
||||
export default {
|
||||
entry: require.resolve('./entry'),
|
||||
hooks: {
|
||||
'rollup:done' ({ rollupConfig }) {
|
||||
consola.info(`Usage: \`node ${relative(process.cwd(), rollupConfig.output.file)} [route]\``)
|
||||
}
|
||||
}
|
||||
}
|
17
packages/nitro/src/targets/cloudflare/entry.ts
Normal file
17
packages/nitro/src/targets/cloudflare/entry.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { render } from '~runtime/server'
|
||||
|
||||
addEventListener('fetch', (event) => {
|
||||
// @ts-ignore
|
||||
event.respondWith(handleRequest(event.request))
|
||||
})
|
||||
|
||||
async function handleRequest (_request) {
|
||||
// @ts-ignore
|
||||
const html = await render()
|
||||
return new Response(html, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'content-type': 'text/html;charset=UTF-8'
|
||||
}
|
||||
})
|
||||
}
|
10
packages/nitro/src/targets/cloudflare/index.ts
Normal file
10
packages/nitro/src/targets/cloudflare/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export default {
|
||||
entry: require.resolve('./entry'),
|
||||
node: false,
|
||||
hooks: {
|
||||
'rollup:config' ({ rollupConfig }) {
|
||||
rollupConfig.output.intro += 'const global = {}; const exports = {}; const module = { exports }; const require = function() {};'
|
||||
rollupConfig.output.format = 'iife'
|
||||
}
|
||||
}
|
||||
}
|
18
packages/nitro/src/targets/vercel/entry.ts
Normal file
18
packages/nitro/src/targets/vercel/entry.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// @ts-ignore
|
||||
import { render } from '~runtime/server'
|
||||
|
||||
module.exports = (req, res) => {
|
||||
const start = process.hrtime()
|
||||
render(req.url).then((html) => {
|
||||
const end = process.hrtime(start)
|
||||
const time = ((end[0] * 1e9) + end[1]) / 1e6
|
||||
// @ts-ignore
|
||||
res.setHeader('X-Nuxt-Coldstart', global._coldstart + 'ms')
|
||||
res.setHeader('X-Nuxt-Responsetime', time + 'ms')
|
||||
|
||||
res.end(html)
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
res.end('Error: ' + err)
|
||||
})
|
||||
}
|
10
packages/nitro/src/targets/vercel/index.ts
Normal file
10
packages/nitro/src/targets/vercel/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import consola from 'consola'
|
||||
|
||||
export default {
|
||||
entry: require.resolve('./entry'),
|
||||
hooks: {
|
||||
'rollup:done' (_ctx) {
|
||||
consola.info('Run `vercel deploy` to deploy!')
|
||||
}
|
||||
}
|
||||
}
|
11
packages/nitro/src/utils.ts
Normal file
11
packages/nitro/src/utils.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { relative } from 'path'
|
||||
import jiti from 'jiti'
|
||||
|
||||
export const hl = str => '`' + str + '`'
|
||||
|
||||
export const prettyPath = (p, highlight = true) => {
|
||||
p = relative(process.cwd(), p)
|
||||
return highlight ? hl(p) : p
|
||||
}
|
||||
|
||||
export const tryImport = (dir, path) => { try { return jiti(dir)(path) } catch (_err) { } }
|
Loading…
Reference in New Issue
Block a user