UNPKG

4.39 kBPlain TextView Raw
1import fs from 'fs'
2import path from 'path'
3
4import * as logger from './log'
5import { createEmitter, createEmitHook, createOnHook } from './createEmitter'
6import { setCurrentPrestaInstance, getCurrentPrestaInstance } from './currentPrestaInstance'
7import { Presta, Config, CLI, Callable } from './types'
8import { Env } from './constants'
9
10const defaultConfigFilepath = 'presta.config.js'
11
12function resolveAbsolutePaths(
13 config: {
14 files?: string | string[]
15 output?: string
16 assets?: string
17 },
18 { cwd }: { cwd: string }
19) {
20 if (config.files) config.files = ([] as string[]).concat(config.files).map((p) => path.resolve(cwd, p))
21 if (config.output) config.output = path.resolve(cwd, config.output)
22 if (config.assets) config.assets = path.resolve(cwd, config.assets)
23 return config
24}
25
26/**
27 * @private
28 */
29export function _clearCurrentConfig() {
30 // @ts-ignore
31 global.__presta__ = {
32 pid: process.pid,
33 cwd: process.cwd(),
34 env: Env.PRODUCTION,
35 }
36}
37
38/**
39 * Fetch a config file. If one was specified by the user, let them know if
40 * anything goes wrong. Outside watch mode, this should exit(1) if the user
41 * provided a config and there was an error
42 */
43export function getConfigFile(filepath?: string, shouldExit: boolean = false) {
44 const fp = path.resolve(filepath || defaultConfigFilepath)
45
46 try {
47 return require(fp)
48 } catch (e) {
49 const exists = fs.existsSync(fp)
50
51 // config file exists, should log error, otherwise ignore missing file
52 if (exists) {
53 logger.error({
54 label: 'error',
55 error: e as Error,
56 })
57
58 // we're not in watch mode, exit build
59 if (shouldExit) process.exit(1)
60 }
61
62 return {}
63 }
64}
65
66/**
67 * Creates a new instance _without_ any values provided by the config file.
68 * This is used when the user deletes their config file.
69 */
70export async function removeConfigValues() {
71 logger.debug({
72 label: 'debug',
73 message: `config file values cleared`,
74 })
75
76 return setCurrentPrestaInstance(
77 await createConfig({
78 ...getCurrentPrestaInstance(),
79 config: {},
80 })
81 )
82}
83
84export async function createConfig({
85 cwd = process.cwd(),
86 env = getCurrentPrestaInstance().env,
87 config = {},
88 cli = {},
89}: {
90 cwd?: string
91 env?: string
92 config?: Partial<Config>
93 cli?: Partial<CLI>
94}) {
95 config = resolveAbsolutePaths({ ...config }, { cwd }) // clone read-only obj
96 cli = resolveAbsolutePaths({ ...cli }, { cwd })
97
98 // combined config, preference to CLI args
99 const merged = {
100 output: path.resolve(cwd, cli.output || config.output || 'build'),
101 assets: path.resolve(cli.assets || config.assets || 'public'),
102 files: cli.files && cli.files.length ? cli.files : config.files ? ([] as string[]).concat(config.files) : [],
103 }
104 const port = cli.port ? parseInt(cli.port) : config.port || 4000
105
106 const previous = getCurrentPrestaInstance()
107 // only create once
108 const emitter = previous.events || createEmitter()
109
110 // deregister old events
111 emitter.clear()
112
113 // set instance
114 const next: Presta = setCurrentPrestaInstance({
115 ...previous,
116 ...merged, // overwrites every time
117 env,
118 cwd,
119 port,
120 debug: cli.debug || getCurrentPrestaInstance().debug,
121 configFilepath: path.resolve(cli.config || defaultConfigFilepath),
122 staticOutputDir: path.join(merged.output, 'static'),
123 functionsOutputDir: path.join(merged.output, 'functions'),
124 functionsManifest: path.join(merged.output, 'routes.json'),
125 events: emitter,
126 hooks: {
127 emitPostBuild(props) {
128 emitter.emit('postBuild', props)
129 },
130 onPostBuild(cb) {
131 return emitter.on('postBuild', cb)
132 },
133 emitBuildFile(props) {
134 emitter.emit('buildFile', props)
135 },
136 onBuildFile(cb) {
137 return emitter.on('buildFile', cb)
138 },
139 emitBrowserRefresh() {
140 emitter.emit('browserRefresh')
141 },
142 onBrowserRefresh(cb) {
143 return emitter.on('browserRefresh', cb)
144 },
145 },
146 })
147
148 if (config.plugins) {
149 await Promise.all(
150 config.plugins.map((p) => {
151 try {
152 return p(getCurrentPrestaInstance)
153 } catch (e) {
154 logger.error({
155 label: 'error',
156 error: e as Error,
157 })
158 }
159 })
160 )
161 }
162
163 logger.debug({
164 label: 'debug',
165 message: `config created ${JSON.stringify(next)}`,
166 })
167
168 return next
169}
170
\No newline at end of file