feat: improved externals and experimental trace with vercel/nft

This commit is contained in:
Pooya Parsa 2020-12-07 22:59:24 +01:00
parent a05c806f85
commit 5bbdc2bc65
4 changed files with 90 additions and 29 deletions

View File

@ -5,6 +5,7 @@ import Hookable, { configHooksT } from 'hookable'
import type { Preset } from '@nuxt/un' import type { Preset } from '@nuxt/un'
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils' import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
import * as PRESETS from './presets' import * as PRESETS from './presets'
import type { NodeExternalsOptions } from './rollup/plugins/externals'
export interface ServerMiddleware { export interface ServerMiddleware {
route: string route: string
@ -18,7 +19,7 @@ export interface SigmaContext {
inlineChunks: boolean inlineChunks: boolean
minify: boolean minify: boolean
sourceMap: boolean sourceMap: boolean
externals: boolean externals: boolean | NodeExternalsOptions
analyze: boolean analyze: boolean
entry: string entry: string
node: boolean node: boolean

View File

@ -1,5 +1,6 @@
import { dirname, join, relative, resolve } from 'upath' import { dirname, join, relative, resolve } from 'upath'
import { InputOptions, OutputOptions } from 'rollup' import { InputOptions, OutputOptions } from 'rollup'
import defu from 'defu'
import { terser } from 'rollup-plugin-terser' import { terser } from 'rollup-plugin-terser'
import commonjs from '@rollup/plugin-commonjs' import commonjs from '@rollup/plugin-commonjs'
import nodeResolve from '@rollup/plugin-node-resolve' import nodeResolve from '@rollup/plugin-node-resolve'
@ -51,6 +52,8 @@ export const getRollupConfig = (sigmaContext: SigmaContext) => {
const env = un.env(nodePreset, builtinPreset, sigmaContext.env) const env = un.env(nodePreset, builtinPreset, sigmaContext.env)
delete env.alias['node-fetch'] // FIX ME
if (sigmaContext.sourceMap) { if (sigmaContext.sourceMap) {
env.polyfill.push('source-map-support/register') env.polyfill.push('source-map-support/register')
} }
@ -165,15 +168,27 @@ export const getRollupConfig = (sigmaContext: SigmaContext) => {
} }
})) }))
// External Plugin const moduleDirectories = [
resolve(sigmaContext._nuxt.rootDir, 'node_modules'),
resolve(MODULE_DIR, 'node_modules'),
resolve(MODULE_DIR, '../node_modules'),
'node_modules'
]
// Externals Plugin
if (sigmaContext.externals) { if (sigmaContext.externals) {
rollupConfig.plugins.push(externals({ rollupConfig.plugins.push(externals(defu(sigmaContext.externals as any, {
relativeTo: sigmaContext.output.serverDir, outDir: sigmaContext.output.serverDir,
include: [ moduleDirectories,
ignore: [
sigmaContext._internal.runtimeDir, sigmaContext._internal.runtimeDir,
...(sigmaContext._nuxt.dev ? [] : [sigmaContext._nuxt.buildDir]),
...sigmaContext.middleware.map(m => m.handle) ...sigmaContext.middleware.map(m => m.handle)
] ],
})) traceOptions: {
base: sigmaContext._nuxt.rootDir
}
})))
} }
// https://github.com/rollup/plugins/tree/master/packages/node-resolve // https://github.com/rollup/plugins/tree/master/packages/node-resolve
@ -181,11 +196,7 @@ export const getRollupConfig = (sigmaContext: SigmaContext) => {
extensions, extensions,
preferBuiltins: true, preferBuiltins: true,
rootDir: sigmaContext._nuxt.rootDir, rootDir: sigmaContext._nuxt.rootDir,
moduleDirectories: [ moduleDirectories,
resolve(sigmaContext._nuxt.rootDir, 'node_modules'),
resolve(MODULE_DIR, 'node_modules'),
'node_modules'
],
mainFields: ['main'] // Force resolve CJS (@vue/runtime-core ssrUtils) mainFields: ['main'] // Force resolve CJS (@vue/runtime-core ssrUtils)
})) }))

View File

@ -1,24 +1,62 @@
import { isAbsolute, relative } from 'upath' import { isAbsolute, relative } from 'path'
import type { Plugin } from 'rollup'
import { resolve, dirname } from 'upath'
import { copyFile, mkdirp } from 'fs-extra'
import { nodeFileTrace, NodeFileTraceOptions } from '@vercel/nft'
export function externals ({ include = [], relativeTo }) { export interface NodeExternalsOptions {
ignore?: string[]
outDir?: string
trace?: boolean
traceOptions?: NodeFileTraceOptions
moduleDirectories?: string[]
}
export function externals (opts: NodeExternalsOptions): Plugin {
const resolvedExternals = {}
return { return {
name: 'externals', name: 'node-externals',
resolveId (source) { resolveId (id) {
if ( // Internals
source[0] === '.' || // Compile relative imports if (id.startsWith('\x00') || id.includes('?')) {
source[0] === '\x00' || // Skip helpers return null
source.includes('?') || // Skip helpers
include.find(i => source.startsWith(i))
) { return null }
if (!isAbsolute(source)) {
source = require.resolve(source)
} }
// Resolve relative paths and exceptions
if (id.startsWith('.') || opts.ignore.find(i => id.startsWith(i))) {
return null
}
for (const dir of opts.moduleDirectories) {
if (id.startsWith(dir)) {
id = id.substr(dir.length + 1)
break
}
}
try {
resolvedExternals[id] = require.resolve(id, { paths: opts.moduleDirectories })
} catch (_err) { }
return { return {
id: relative(relativeTo, source), id: isAbsolute(id) ? relative(opts.outDir, id) : id,
external: true external: true
} }
},
async buildEnd () {
if (opts.trace) {
const { fileList } = await nodeFileTrace(Object.values(resolvedExternals), opts.traceOptions)
await Promise.all(fileList.map(async (file) => {
if (!file.startsWith('node_modules')) {
return
}
// TODO: Minify package.json
const src = resolve(opts.traceOptions.base, file)
const dst = resolve(opts.outDir, file)
await mkdirp(dirname(dst))
await copyFile(src, dst)
}))
}
} }
} }
} }

View File

@ -6,7 +6,7 @@ import { readFile } from 'fs-extra'
import chalk from 'chalk' import chalk from 'chalk'
export async function printFSTree (dir) { export async function printFSTree (dir) {
const files = await globby('**/*.js', { cwd: dir }) const files = await globby('**/*.*', { cwd: dir })
const items = (await Promise.all(files.map(async (file) => { const items = (await Promise.all(files.map(async (file) => {
const path = resolve(dir, file) const path = resolve(dir, file)
@ -19,16 +19,27 @@ export async function printFSTree (dir) {
let totalSize = 0 let totalSize = 0
let totalGzip = 0 let totalGzip = 0
let totalNodeModulesSize = 0
let totalNodeModulesGzip = 0
items.forEach((item, index) => { items.forEach((item, index) => {
let dir = dirname(item.file) let dir = dirname(item.file)
if (dir === '.') { dir = '' } if (dir === '.') { dir = '' }
const rpath = relative(process.cwd(), item.path) const rpath = relative(process.cwd(), item.path)
const treeChar = index === items.length - 1 ? '└─' : '├─' const treeChar = index === items.length - 1 ? '└─' : '├─'
process.stdout.write(chalk.gray(` ${treeChar} ${rpath} (${prettyBytes(item.size)}) (${prettyBytes(item.gzip)} gzip)\n`))
const isNodeModules = item.file.includes('node_modules')
if (isNodeModules) {
totalNodeModulesSize += item.size
totalNodeModulesGzip += item.gzip
return
}
process.stdout.write(chalk.gray(` ${treeChar} ${rpath} (${prettyBytes(item.size)}) (${prettyBytes(item.gzip)} gzip)\n`))
totalSize += item.size totalSize += item.size
totalGzip += item.gzip totalGzip += item.gzip
}) })
process.stdout.write(`${chalk.cyan('Σ Total size:')} ${prettyBytes(totalSize)} (${prettyBytes(totalGzip)} gzip)\n`) process.stdout.write(`${chalk.cyan('Σ Total size:')} ${prettyBytes(totalSize + totalNodeModulesSize)} (${prettyBytes(totalGzip + totalNodeModulesGzip)} gzip)\n`)
} }