Skip to content

Commit

Permalink
feat: support dynamic chunks, lazy middleware and cjs target
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Nov 14, 2020
1 parent a3fb537 commit 0caa11e
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 142 deletions.
15 changes: 8 additions & 7 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,27 @@ import Hookable from 'hookable'
import prettyBytes from 'pretty-bytes'
import gzipSize from 'gzip-size'
import chalk from 'chalk'
import { readFile } from 'fs-extra'
import { readFile, emptyDir } from 'fs-extra'
import { getRollupConfig } from './rollup/config'
import { hl, prettyPath, serializeTemplate, writeFile } from './utils'
import { SLSOptions } from './config'

export async function build (options: SLSOptions) {
console.log('\n')
consola.info(`Generating bundle for ${hl(options.target)}`)

const hooks = new Hookable()
hooks.addHooks(options.hooks)

if (options.cleanTargetDir) {
await emptyDir(options.targetDir)
}

// Compile html template
const htmlSrc = resolve(options.buildDir, `views/${{ 2: 'app', 3: 'document' }[2]}.template.html`)
const htmlTemplate = { src: htmlSrc, contents: '', dst: '', compiled: '' }
htmlTemplate.dst = htmlTemplate.src.replace(/.html$/, '.js').replace('app.', 'document.')
htmlTemplate.contents = await readFile(htmlTemplate.src, 'utf-8')
htmlTemplate.compiled = serializeTemplate(htmlTemplate.contents)
htmlTemplate.compiled = 'module.exports = ' + serializeTemplate(htmlTemplate.contents)
await hooks.callHook('template:document', htmlTemplate)
await writeFile(htmlTemplate.dst, htmlTemplate.compiled)

Expand All @@ -36,13 +39,11 @@ export async function build (options: SLSOptions) {
const { output } = await build.write(options.rollupConfig.output as OutputOptions)
const size = prettyBytes(output[0].code.length)
const zSize = prettyBytes(await gzipSize(output[0].code))
consola.success('Generated', prettyPath((options.rollupConfig.output as any).file),
chalk.gray(`(Size: ${size} Gzip: ${zSize})`)
)
consola.success('Generated bundle in', prettyPath(options.targetDir), chalk.gray(`(Size: ${size} Gzip: ${zSize})`))

await hooks.callHook('done', options)

return {
entry: options.rollupConfig.output.file
entry: resolve(options.rollupConfig.output.dir, options.rollupConfig.output.entryFileNames)
}
}
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface Nuxt extends Hookable{
export interface ServerMiddleware {
route: string
handle: string
lazy?: boolean
}

export interface SLSOptions {
Expand All @@ -34,11 +35,13 @@ export interface SLSOptions {
node: false | true
target: string
minify: boolean
externals: boolean
rollupConfig?: any
logStartup: boolean
inlineChunks: boolean
renderer: string
analyze: boolean
cleanTargetDir: boolean

runtimeDir: string
slsDir: string
Expand Down Expand Up @@ -72,6 +75,8 @@ export function getoptions (nuxtOptions: Nuxt['options'], serverless: SLSConfig)
logStartup: true,
inlineChunks: true,
minify: false,
externals: false,
cleanTargetDir: true,

runtimeDir: resolve(__dirname, '../runtime'),
slsDir: '{{ rootDir }}/.nuxt/serverless',
Expand Down
14 changes: 8 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ export default <Module> function slsModule () {
const options = getoptions(nuxt.options, nuxt.options.serverless || {})

// Tune webpack config
if (options.minify !== false) {
nuxt.options.build._minifyServer = true
}
nuxt.options.build._minifyServer = options.minify !== false
nuxt.options.build.standalone = true

// Tune generator
Expand Down Expand Up @@ -46,7 +44,7 @@ export default <Module> function slsModule () {
continue
}

options.serverMiddleware.push({ route, handle })
options.serverMiddleware.push({ ...m, route, handle })
}
if (unsupported.length) {
console.warn('[serverless] Unsupported Server middleware used: ', unsupported)
Expand All @@ -72,12 +70,16 @@ export default <Module> function slsModule () {
})

nuxt.hook('generate:before', async () => {
console.info('Building light version for `nuxt generate`')
const { entry } = await build(getoptions(nuxt.options, {
target: 'node',
target: 'cjs',
serverMiddleware: options.serverMiddleware
}))
console.info('Loading lambda')
require(entry)
})

nuxt.hook('generate:done', () => build(options))
nuxt.hook('generate:done', async () => {
await build(options)
})
}
126 changes: 72 additions & 54 deletions src/rollup/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Module from 'module'
import { basename, dirname, extname, resolve } from 'path'
import { join, resolve } from 'path'
import { InputOptions, OutputOptions } from 'rollup'
import { terser } from 'rollup-plugin-terser'
import commonjs from '@rollup/plugin-commonjs'
Expand All @@ -13,23 +13,18 @@ import analyze from 'rollup-plugin-analyzer'

import hasha from 'hasha'
import { SLSOptions } from '../config'
import { resolvePath } from '../utils'
import dynamicRequire from './dynamic-require'
import { resolvePath, MODULE_DIR } from '../utils'
import { dynamicRequire } from './dynamic-require'
import { externals } from './externals'

const mapArrToVal = (val, arr) => arr.reduce((p, c) => ({ ...p, [c]: val }), {})

export type RollupConfig = InputOptions & { output: OutputOptions }

export const getRollupConfig = (config: SLSOptions) => {
const providedDeps = [
'@nuxt/devalue',
'vue-bundle-renderer',
'@cloudflare/kv-asset-handler'
]

export const getRollupConfig = (options: SLSOptions) => {
const extensions: string[] = ['.ts', '.mjs', '.js', '.json', '.node']

const external: string[] = []
const external: InputOptions['external'] = []

const injects:{ [key: string]: string| string[] } = {}

Expand All @@ -53,7 +48,10 @@ export const getRollupConfig = (config: SLSOptions) => {
'@vue/compiler-ssr'
]))

if (config.node === false) {
// Uses eval
aliases.depd = '~mocks/custom/depd'

if (options.node === false) {
// Globals
// injects.Buffer = ['buffer', 'Buffer'] <-- TODO: Make it opt-in
injects.process = '~mocks/node/process'
Expand All @@ -73,7 +71,6 @@ export const getRollupConfig = (config: SLSOptions) => {

// Custom
'node-fetch': '~mocks/custom/node-fetch',
depd: '~mocks/custom/depd',
etag: '~mocks/generic/noop',

// Express
Expand All @@ -91,13 +88,15 @@ export const getRollupConfig = (config: SLSOptions) => {
external.push(...Module.builtinModules)
}

const outFile = resolve(config.targetDir, config.outName)

const options: RollupConfig = {
input: resolvePath(config, config.entry),
const rollupConfig: RollupConfig = {
input: resolvePath(options, options.entry),
output: {
file: outFile,
dir: options.targetDir,
entryFileNames: options.outName,
chunkFileNames: 'chunks/_[name].js',
inlineDynamicImports: options.inlineChunks,
format: 'cjs',
exports: 'auto',
intro: '',
outro: '',
preferConst: true
Expand All @@ -106,31 +105,32 @@ export const getRollupConfig = (config: SLSOptions) => {
plugins: []
}

if (config.logStartup) {
options.output.intro += 'global._startTime = global.process.hrtime();'
if (options.logStartup) {
rollupConfig.output.intro += 'global._startTime = global.process.hrtime();'
// eslint-disable-next-line no-template-curly-in-string
options.output.outro += 'global._endTime = global.process.hrtime(global._startTime); global._coldstart = ((global._endTime[0] * 1e9) + global._endTime[1]) / 1e6; console.log(`λ Cold start took: ${global._coldstart}ms`);'
rollupConfig.output.outro += 'global._endTime = global.process.hrtime(global._startTime); global._coldstart = ((global._endTime[0] * 1e9) + global._endTime[1]) / 1e6; console.log(`λ Cold start took: ${global._coldstart}ms (${typeof __filename !== "undefined" ? __filename.replace(process.cwd(), "") : "<entry>"})`);'
}

// https://github.com/rollup/plugins/tree/master/packages/replace
options.plugins.push(replace({
rollupConfig.plugins.push(replace({
values: {
'process.env.NODE_ENV': '"production"',
'typeof window': '"undefined"',
'process.env.ROUTER_BASE': JSON.stringify(config.routerBase),
'process.env.PUBLIC_PATH': JSON.stringify(config.publicPath),
'process.env.NUXT_STATIC_BASE': JSON.stringify(config.staticAssets.base),
'process.env.NUXT_STATIC_VERSION': JSON.stringify(config.staticAssets.version),
'process.env.ROUTER_BASE': JSON.stringify(options.routerBase),
'process.env.PUBLIC_PATH': JSON.stringify(options.publicPath),
'process.env.NUXT_STATIC_BASE': JSON.stringify(options.staticAssets.base),
'process.env.NUXT_STATIC_VERSION': JSON.stringify(options.staticAssets.version),
// @ts-ignore
'process.env.NUXT_FULL_STATIC': config.fullStatic
'process.env.NUXT_FULL_STATIC': options.fullStatic
}
}))

// Dynamic Require Support
options.plugins.push(dynamicRequire({
dir: resolve(config.buildDir, 'dist/server'),
outDir: (config.node === false || config.inlineChunks) ? undefined : dirname(outFile),
chunksDir: '_' + basename(outFile, extname(outFile)),
rollupConfig.plugins.push(dynamicRequire({
dir: resolve(options.buildDir, 'dist/server'),
inline: options.node === false || options.inlineChunks,
outDir: join(options.targetDir, 'chunks'),
prefix: './',
globbyOptions: {
ignore: [
'server.js'
Expand All @@ -140,7 +140,7 @@ export const getRollupConfig = (config: SLSOptions) => {

// https://github.com/rollup/plugins/tree/master/packages/replace
// TODO: better fix for node-fetch issue
options.plugins.push(replace({
rollupConfig.plugins.push(replace({
delimiters: ['', ''],
values: {
'require(\'encoding\')': '{}'
Expand All @@ -149,59 +149,77 @@ export const getRollupConfig = (config: SLSOptions) => {

// Provide serverMiddleware
const getImportId = p => '_' + hasha(p).substr(0, 6)
options.plugins.push(virtual({
rollupConfig.plugins.push(virtual({
'~serverMiddleware': `
${config.serverMiddleware.map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
${options.serverMiddleware.filter(m => !m.lazy).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
${options.serverMiddleware.filter(m => m.lazy).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
export default [
${config.serverMiddleware.map(m => `{ route: '${m.route}', handle: ${getImportId(m.handle)} }`).join(',\n')}
${options.serverMiddleware.map(m => `{ route: '${m.route}', handle: ${getImportId(m.handle)}, lazy: ${m.lazy || false} }`).join(',\n')}
];
`
}))

// https://github.com/rollup/plugins/tree/master/packages/alias
const renderer = config.renderer || 'vue2'
options.plugins.push(alias({
const renderer = options.renderer || 'vue2'
rollupConfig.plugins.push(alias({
entries: {
'~runtime': config.runtimeDir,
'~mocks': resolve(config.runtimeDir, 'mocks'),
'~renderer': require.resolve(resolve(config.runtimeDir, 'ssr', renderer)),
'~build': config.buildDir,
'~mock': require.resolve(resolve(config.runtimeDir, 'mocks/generic')),
...providedDeps.reduce((p, c) => ({ ...p, [c]: require.resolve(c) }), {}),
'~runtime': options.runtimeDir,
'~mocks': resolve(options.runtimeDir, 'mocks'),
'~renderer': require.resolve(resolve(options.runtimeDir, 'ssr', renderer)),
'~build': options.buildDir,
'~mock': require.resolve(resolve(options.runtimeDir, 'mocks/generic')),
...aliases
}
}))

// External Plugin
if (options.externals) {
rollupConfig.plugins.push(externals({
relativeTo: options.targetDir,
include: [
options.runtimeDir,
...options.serverMiddleware.map(m => m.handle)
]
}))
}

// https://github.com/rollup/plugins/tree/master/packages/node-resolve
options.plugins.push(nodeResolve({
rollupConfig.plugins.push(nodeResolve({
extensions,
preferBuiltins: true,
rootDir: config.rootDir,
rootDir: options.rootDir,
// https://www.npmjs.com/package/resolve
customResolveOptions: { basedir: config.rootDir },
customResolveOptions: {
basedir: options.rootDir,
paths: [
resolve(options.rootDir, 'node_modukes'),
resolve(MODULE_DIR, 'node_modules')
]
},
mainFields: ['main'] // Force resolve CJS (@vue/runtime-core ssrUtils)
}))

// https://github.com/rollup/plugins/tree/master/packages/commonjs
options.plugins.push(commonjs({
rollupConfig.plugins.push(commonjs({
extensions: extensions.filter(ext => ext !== '.json')
}))

// https://github.com/rollup/plugins/tree/master/packages/json
options.plugins.push(json())
rollupConfig.plugins.push(json())

// https://github.com/rollup/plugins/tree/master/packages/inject
options.plugins.push(inject(injects))
rollupConfig.plugins.push(inject(injects))

if (config.analyze) {
if (options.analyze) {
// https://github.com/doesdev/rollup-plugin-analyzer
options.plugins.push(analyze())
rollupConfig.plugins.push(analyze())
}

if (config.minify !== false) {
options.plugins.push(terser())
if (options.minify !== false) {
rollupConfig.plugins.push(terser())
}

return options
return rollupConfig
}
Loading

0 comments on commit 0caa11e

Please sign in to comment.