Skip to content

Commit

Permalink
wip: mode resolution + build env replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Dec 18, 2020
1 parent 9447c66 commit 4a955bc
Show file tree
Hide file tree
Showing 15 changed files with 615 additions and 50 deletions.
4 changes: 4 additions & 0 deletions packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@rollup/plugin-node-resolve": "^11.0.1",
"@rollup/plugin-typescript": "^8.0.0",
"@rollup/pluginutils": "^4.1.0",
"@types/clean-css": "^4.2.3",
"@types/debug": "^4.1.5",
"@types/es-module-lexer": "^0.3.0",
"@types/etag": "^1.8.0",
Expand All @@ -66,9 +67,11 @@
"@types/ws": "^7.4.0",
"acorn": "^8.0.4",
"acorn-class-fields": "^0.3.7",
"brotli-size": "^4.0.0",
"cac": "^6.6.1",
"chalk": "^4.1.0",
"chokidar": "^3.4.3",
"clean-css": "^4.2.3",
"connect": "^3.7.0",
"connect-history-api-fallback": "^1.6.0",
"cors": "^2.8.5",
Expand All @@ -88,6 +91,7 @@
"postcss-load-config": "^3.0.0",
"postcss-modules": "^4.0.0",
"resolve": "^1.19.0",
"rollup-plugin-dynamic-import-variables": "^1.1.0",
"rollup-plugin-terser": "^7.0.2",
"selfsigned": "^1.10.8",
"sirv": "^1.0.10",
Expand Down
24 changes: 10 additions & 14 deletions packages/vite/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ const nodeConfig = {
'utf-8-validate': 1
}),
commonjs(),
json()
json(),
{
name: 'inspect',
generateBundle(_, output) {
debugger
}
}
],
treeshake: {
moduleSideEffects: 'no-external',
Expand All @@ -87,22 +93,12 @@ const nodeConfig = {
},
output: {
dir: path.resolve(__dirname, 'dist/node'),
entryFileNames(chunk) {
if (chunk.name === 'server') {
return `server/index.js`
}
return `[name].js`
},
chunkFileNames: 'chunks/[name].js',
entryFileNames: `[name].js`,
chunkFileNames: 'chunks/dep-[hash].js',
exports: 'named',
format: 'cjs',
externalLiveBindings: false,
freeze: false,
manualChunks(id) {
if (id.includes('node_modules')) {
return 'deps'
}
}
freeze: false
},
onwarn(warning, warn) {
// node-resolve complains a lot about this but seems to still work?
Expand Down
211 changes: 210 additions & 1 deletion packages/vite/src/node/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,214 @@
import path from 'path'
import { resolveConfig, UserConfig } from '../config'
import Rollup, { Plugin, RollupBuild, RollupOptions } from 'rollup'
import { Options as RollupTerserOptions } from 'rollup-plugin-terser'
import { sizeReporPlugin } from '../plugins/size'
import { buildDefinePlugin } from '../plugins/define'

export interface BuildOptions {
/**
* Entry. Use this to specify a js entry file in use cases where an
* `index.html` does not exist (e.g. serving vite assets from a different host)
* @default 'index.html'
*/
entry?: string
/**
* Base public path when served in production.
* @default '/'
*/
base?: string
/**
* Directory relative from `root` where build output will be placed. If the
* directory exists, it will be removed before the build.
* @default 'dist'
*/
outDir?: string
/**
* Directory relative from `outDir` where the built js/css/image assets will
* be placed.
* @default '_assets'
*/
assetsDir?: string
/**
* Static asset files smaller than this number (in bytes) will be inlined as
* base64 strings. Default limit is `4096` (4kb). Set to `0` to disable.
* @default 4096
*/
assetsInlineLimit?: number
/**
* Whether to code-split CSS. When enabled, CSS in async chunks will be
* inlined as strings in the chunk and inserted via dynamically created
* style tags when the chunk is loaded.
* @default true
*/
cssCodeSplit?: boolean
/**
* Whether to generate sourcemap
* @default false
*/
sourcemap?: boolean | 'inline'
/**
* Set to `false` to disable minification, or specify the minifier to use.
* Available options are 'terser' or 'esbuild'.
* @default 'terser'
*/
minify?: boolean | 'terser' | 'esbuild'
/**
* The option for `terser`
* TODO inline the type
*/
terserOptions?: RollupTerserOptions
/**
* Build for server-side rendering, only as a CLI flag
* for programmatic usage, use `ssrBuild` directly.
* @internal
*/
ssr?: boolean
/**
* Will be merged with internal rollup options.
* https://rollupjs.org/guide/en/#big-list-of-options
*/
rollupOptions?: RollupOptions
/**
* Whether to write bundle to disk
* @default true
*/
write?: boolean
/**
* Whether to emit index.html
* @default true
*/
emitIndex?: boolean
/**
* Whether to emit assets other than JavaScript
* @default true
*/
emitAssets?: boolean
/**
* Whether to emit a manifest.json under assets dir to map hash-less filenames
* to their hashed versions. Useful when you want to generate your own HTML
* instead of using the one generated by Vite.
*
* Example:
*
* ```json
* {
* "main.js": "main.68fe3fad.js",
* "style.css": "style.e6b63442.css"
* }
* ```
* @default false
*/
emitManifest?: boolean
}

export type BuildHook = (options: BuildOptions) => BuildOptions | void

export function resolveBuildOptions(
raw?: BuildOptions
): Required<BuildOptions> {
const resolved: Required<BuildOptions> = {
entry: 'index.html',
base: '/',
outDir: 'dist',
assetsDir: '_assets',
assetsInlineLimit: 4096,
cssCodeSplit: true,
sourcemap: false,
minify: 'terser',
terserOptions: {},
ssr: false,
rollupOptions: {},
write: true,
emitIndex: true,
emitAssets: true,
emitManifest: false,
...raw
}

// ensure base ending slash
resolved.base = resolved.base.replace(/([^/])$/, '$1/')

return resolved
}

/**
* Track parallel build calls and only stop the esbuild service when all
* builds are done. (#1098)
*/
let parallelCallCounts = 0
// we use a separate counter to track since the call may error before the
// bundle is even pushed.
const paralellBuilds: RollupBuild[] = []

/**
* Bundles the app for production.
* Returns a Promise containing the build result.
*/
export async function build(
inlineConfig: UserConfig = {},
mode = 'production',
configPath?: string | false
) {
parallelCallCounts++
try {
return await doBuild(inlineConfig, mode, configPath)
} finally {
parallelCallCounts--
if (parallelCallCounts <= 0) {
paralellBuilds.forEach((bundle) => bundle.close())
paralellBuilds.length = 0
}
}
}

export type BuildHook = () => void
async function doBuild(
inlineConfig: UserConfig = {},
mode: string,
configPath?: string | false
) {
const config = await resolveConfig(inlineConfig, 'build', mode, configPath)
const options = config.build

const resolve = (p: string) => path.resolve(config.root, p)

const input = resolve(options.entry)
const outDir = resolve(options.outDir)
const assetsDir = path.resolve(outDir, options.assetsDir)

const plugins = [
...(config.plugins as Plugin[]),
...(options.rollupOptions.plugins || []),
buildDefinePlugin(config),
...(options.minify
? options.minify === 'esbuild'
? [] // TODO
: [(await import('rollup-plugin-terser')).terser(options.terserOptions)]
: []),
sizeReporPlugin(options)
]

const rollup = require('rollup') as typeof Rollup
const bundle = await rollup.rollup({
input,
preserveEntrySignatures: false,
treeshake: { moduleSideEffects: 'no-external' },
...options.rollupOptions,
plugins
})

paralellBuilds.push(bundle)

await bundle[options.write ? 'write' : 'generate']({
dir: assetsDir,
format: 'es',
sourcemap: options.sourcemap,
entryFileNames: `[name].[hash].js`,
chunkFileNames: `[name].[hash].js`,
assetFileNames: `[name].[hash].[ext]`,
// #764 add `Symbol.toStringTag` when build es module into cjs chunk
// #1048 add `Symbol.toStringTag` for module default export
namespaceToStringTag: true,
...options.rollupOptions.output
})
}
41 changes: 38 additions & 3 deletions packages/vite/src/node/cli.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cac } from 'cac'
import chalk from 'chalk'
import { BuildOptions } from './build'
import { build, BuildOptions } from './build'
import { startServer, ServerOptions } from './server'

const cli = cac('vite')
Expand Down Expand Up @@ -54,7 +54,7 @@ cli
.action((root: string, options: ServerOptions & GlobalCLIOptions) => {
// output structure is preserved even after bundling so require()
// is ok here
const start = require('./server/index').startServer as typeof startServer
const start = require('./server').startServer as typeof startServer
start(
{
root,
Expand All @@ -72,11 +72,46 @@ cli
// build
cli
.command('build [root]')
.option(
'--entry <file>',
`[string] entry file for build (default: index.html)`
)
.option('--base <path>', `[string] public base path (default: /)`)
.option('--outDir <dir>', `[string]  output directory (default: dist)`)
.option(
'--assetsDir <dir>',
`[string] directory under outDir to place assets in (default: _assets)`
)
.option(
'--assetsInlineLimit <number>',
`[number] static asset base64 inline threshold in bytes (default: 4096)`
)
.option('--ssr', `[boolean] build for server-side rendering`)
.option(
'--sourcemap',
`[boolean] output source maps for build (default: false)`
)
.option(
'--minify [minifier]',
`[boolean | 'terser' | 'esbuild'] enable/disable minification, or specify minifier to use (default: terser)`
)
.option('--mode <mode>', `[string] set env mode`, {
default: 'production'
})
.action((root: string, options: BuildOptions & GlobalCLIOptions) => {
console.log('build!', cleanOptions(options))
const runBuild = require('./build').build as typeof build
runBuild(
{
root,
build: cleanOptions(options) as BuildOptions
},
options.mode,
options.config
).catch((e) => {
console.log(chalk.red('[vite] build failed.'))
console.error(e.stack)
process.exit(1)
})
})

cli.help()
Expand Down
15 changes: 9 additions & 6 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs'
import path from 'path'
import { Plugin } from './plugin'
import Rollup, { RollupOptions } from 'rollup'
import { BuildOptions } from './build'
import { BuildOptions, resolveBuildOptions } from './build'
import { ServerOptions } from './server'
import { CSSOptions } from './plugins/css'
import { createDebugger, deepMerge, isObject, lookupFile } from './utils'
Expand Down Expand Up @@ -94,7 +94,7 @@ export type ResolvedConfig = Readonly<
env: Record<string, any>
plugins: readonly Plugin[]
server: ServerOptions
build: BuildOptions
build: Required<BuildOptions>
assetsInclude: (file: string) => boolean
}
>
Expand Down Expand Up @@ -166,9 +166,9 @@ export async function resolveConfig(

// Note it is possible for user to have a custom mode, e.g. `staging` where
// production-like behavior is expected. This is indicated by NODE_ENV=production
// loaded from `.staging.env`.
const isProduction =
process.env.NODE_ENV === 'production' || mode === 'production'
// loaded from `.staging.env` and set by us as VITE_USER_NODE_ENV
const resolvedMode = process.env.VITE_USER_NODE_ENV || mode
const isProduction = resolvedMode === 'production'

const resolved = {
...config,
Expand All @@ -180,7 +180,7 @@ export async function resolveConfig(
alias: resolvedAlias,
plugins: userPlugins,
server: config.server || {},
build: config.build || {},
build: resolveBuildOptions(config.build),
assetsInclude: (file: string) => {
return (
DEFAULT_ASSETS_RE.test(file) || config.assetsInclude?.(file) || false
Expand Down Expand Up @@ -374,6 +374,9 @@ function loadEnv(mode: string, root: string, prefix = 'VITE_') {
for (const [key, value] of Object.entries(parsed)) {
if (key.startsWith(prefix) && env[key] === undefined) {
env[key] = value
} else if (key === 'NODE_ENV') {
// NODE_ENV override in .env file
process.env.VITE_USER_NODE_ENV = value
}
}
}
Expand Down

0 comments on commit 4a955bc

Please sign in to comment.