@eighty4/dank 0.0.2 → 0.0.4-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib_js/build.js CHANGED
@@ -1,70 +1,95 @@
1
- import { mkdir, rm } from 'node:fs/promises';
1
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { isProductionBuild, willMinify } from "./flags.js";
4
- import { copyAssets } from "./public.js";
5
- import { createBuildTag } from "./tag.js";
6
- import { writeBuildManifest, writeMetafile } from "./manifest.js";
3
+ import { createBuildTag } from "./build_tag.js";
7
4
  import { createGlobalDefinitions } from "./define.js";
5
+ import { esbuildWebpages, esbuildWorkers } from "./esbuild.js";
6
+ import { resolveBuildFlags } from "./flags.js";
8
7
  import { HtmlEntrypoint } from "./html.js";
9
- import { esbuildWebpages } from "./esbuild.js";
10
- export async function buildWebsite(c) {
11
- const buildDir = 'build';
12
- const distDir = join(buildDir, 'dist');
13
- const buildTag = await createBuildTag();
14
- console.log(willMinify()
15
- ? isProductionBuild()
8
+ import { WebsiteRegistry } from "./metadata.js";
9
+ import { copyAssets } from "./public.js";
10
+ export async function buildWebsite(c, build = resolveBuildFlags()) {
11
+ const buildTag = await createBuildTag(build);
12
+ console.log(build.minify
13
+ ? build.production
16
14
  ? 'minified production'
17
15
  : 'minified'
18
16
  : 'unminified', 'build', buildTag, 'building in ./build/dist');
19
- await rm(buildDir, { recursive: true, force: true });
20
- await mkdir(distDir, { recursive: true });
21
- await mkdir(join(buildDir, 'metafiles'), { recursive: true });
22
- const staticAssets = await copyAssets(distDir);
23
- const buildUrls = [];
24
- buildUrls.push(...(await buildWebpages(distDir, createGlobalDefinitions(), c.pages)));
25
- if (staticAssets) {
26
- buildUrls.push(...staticAssets);
17
+ await rm(build.dirs.buildRoot, { recursive: true, force: true });
18
+ await mkdir(build.dirs.buildDist, { recursive: true });
19
+ for (const subdir of Object.keys(c.pages).filter(url => url !== '/')) {
20
+ await mkdir(join(build.dirs.buildDist, subdir), { recursive: true });
27
21
  }
28
- const result = new Set(buildUrls);
29
- await writeBuildManifest(buildTag, result);
30
- return {
31
- dir: distDir,
32
- files: result,
33
- };
22
+ await mkdir(join(build.dirs.buildRoot, 'metafiles'), { recursive: true });
23
+ const registry = new WebsiteRegistry(build);
24
+ registry.pageUrls = Object.keys(c.pages);
25
+ registry.copiedAssets = await copyAssets(build);
26
+ await buildWebpages(c, registry, build, createGlobalDefinitions(build));
27
+ return await registry.writeManifest(buildTag);
34
28
  }
35
- async function buildWebpages(distDir, define, pages) {
36
- const entryPointUrls = new Set();
37
- const entryPoints = [];
38
- const htmlEntrypoints = await Promise.all(Object.entries(pages).map(async ([urlPath, fsPath]) => {
39
- const html = await HtmlEntrypoint.readFrom(urlPath, join('pages', fsPath));
40
- await html.injectPartials();
41
- if (urlPath !== '/') {
42
- await mkdir(join(distDir, urlPath), { recursive: true });
29
+ // builds all webpage entrypoints in one esbuild.build context
30
+ // to support code splitting
31
+ // returns all built assets URLs and webpage URLs from DankConfig.pages
32
+ async function buildWebpages(c, registry, build, define) {
33
+ // create HtmlEntrypoint for each webpage and collect awaitable esbuild entrypoints
34
+ const loadingEntryPoints = [];
35
+ const htmlEntrypoints = [];
36
+ for (const [urlPath, mapping] of Object.entries(c.pages)) {
37
+ const fsPath = typeof mapping === 'string' ? mapping : mapping.webpage;
38
+ const html = new HtmlEntrypoint(build, urlPath, fsPath);
39
+ loadingEntryPoints.push(new Promise(res => html.on('entrypoints', res)));
40
+ htmlEntrypoints.push(html);
41
+ }
42
+ // collect esbuild entrypoints from every HtmlEntrypoint
43
+ const uniqueEntryPoints = new Set();
44
+ const buildEntryPoints = [];
45
+ for (const pageEntryPoints of await Promise.all(loadingEntryPoints)) {
46
+ for (const entryPoint of pageEntryPoints) {
47
+ if (!uniqueEntryPoints.has(entryPoint.in)) {
48
+ buildEntryPoints.push(entryPoint);
49
+ }
43
50
  }
44
- html.collectScripts()
45
- .filter(scriptImport => !entryPointUrls.has(scriptImport.in))
46
- .forEach(scriptImport => {
47
- entryPointUrls.add(scriptImport.in);
48
- entryPoints.push({
49
- in: scriptImport.in,
50
- out: scriptImport.out,
51
- });
52
- });
53
- return html;
54
- }));
55
- const metafile = await esbuildWebpages(define, entryPoints, distDir);
56
- await writeMetafile(`pages.json`, metafile);
57
- // todo these hrefs would have \ path separators on windows
58
- const buildUrls = [...Object.keys(pages)];
59
- const mapInToOutHrefs = {};
60
- for (const [outputFile, { entryPoint }] of Object.entries(metafile.outputs)) {
61
- const outputUrl = outputFile.replace(/^build\/dist/, '');
62
- buildUrls.push(outputUrl);
63
- mapInToOutHrefs[entryPoint] = outputUrl;
64
51
  }
52
+ await esbuildWebpages(build, registry, define, buildEntryPoints, c.esbuild);
53
+ // todo recursively build workers on building workers that create workers
54
+ const workerEntryPoints = registry.workerEntryPoints();
55
+ if (workerEntryPoints?.length) {
56
+ await esbuildWorkers(build, registry, define, workerEntryPoints, c.esbuild);
57
+ }
58
+ await rewriteWorkerUrls(build, registry);
59
+ // write out html output with rewritten hrefs
65
60
  await Promise.all(htmlEntrypoints.map(async (html) => {
66
- html.rewriteHrefs(mapInToOutHrefs);
67
- await html.writeTo(distDir);
61
+ await writeFile(join(build.dirs.buildDist, html.url, 'index.html'), html.output(registry));
62
+ }));
63
+ }
64
+ export async function rewriteWorkerUrls(build, registry) {
65
+ const workers = registry.workers();
66
+ if (!workers) {
67
+ return;
68
+ }
69
+ const dependentBundlePaths = workers.map(w => registry.mappedHref(w.dependentEntryPoint));
70
+ const bundleOutputs = {};
71
+ // collect all js file contents concurrently
72
+ const readingFiles = Promise.all(dependentBundlePaths.map(async (p) => {
73
+ bundleOutputs[p] = await readFile(join(build.dirs.projectRootAbs, build.dirs.buildDist, p), 'utf8');
74
+ }));
75
+ // build regex replacements during file reads
76
+ const rewriteChains = {};
77
+ for (const p of dependentBundlePaths)
78
+ rewriteChains[p] = [];
79
+ for (const w of workers) {
80
+ rewriteChains[registry.mappedHref(w.dependentEntryPoint)].push(s => s.replace(createWorkerRegex(w.workerUrlPlaceholder), `new Worker('${registry.mappedHref(w.workerEntryPoint)}')`));
81
+ }
82
+ // wait for file reads
83
+ await readingFiles;
84
+ // run rewrite regex chain and write back to dist
85
+ await Promise.all(Object.entries(bundleOutputs).map(async ([p, content]) => {
86
+ let result = content;
87
+ for (const rewriteFn of rewriteChains[p]) {
88
+ result = rewriteFn(result);
89
+ }
90
+ await writeFile(join(build.dirs.projectRootAbs, build.dirs.buildDist, p), result);
68
91
  }));
69
- return buildUrls;
92
+ }
93
+ export function createWorkerRegex(workerUrl) {
94
+ return new RegExp(`new(?:\\s|\\r?\\n)+Worker(?:\\s|\\r?\\n)*\\((?:\\s|\\r?\\n)*['"]${workerUrl}['"](?:\\s|\\r?\\n)*\\)`, 'g');
70
95
  }
@@ -1,6 +1,5 @@
1
1
  import { exec } from 'node:child_process';
2
- import { isProductionBuild } from "./flags.js";
3
- export async function createBuildTag() {
2
+ export async function createBuildTag(build) {
4
3
  const now = new Date();
5
4
  const ms = now.getUTCMilliseconds() +
6
5
  now.getUTCSeconds() * 1000 +
@@ -9,7 +8,7 @@ export async function createBuildTag() {
9
8
  const date = now.toISOString().substring(0, 10);
10
9
  const time = String(ms).padStart(8, '0');
11
10
  const when = `${date}-${time}`;
12
- if (isProductionBuild()) {
11
+ if (build.production) {
13
12
  const gitHash = await new Promise((res, rej) => exec('git rev-parse --short HEAD', (err, stdout) => {
14
13
  if (err)
15
14
  rej(err);
package/lib_js/dank.js CHANGED
@@ -1,21 +1,76 @@
1
1
  export async function defineConfig(c) {
2
+ if (c.port !== null && typeof c.port !== 'undefined') {
3
+ if (typeof c.port !== 'number') {
4
+ throw Error('DankConfig.port must be a number');
5
+ }
6
+ }
7
+ if (c.previewPort !== null && typeof c.previewPort !== 'undefined') {
8
+ if (typeof c.previewPort !== 'number') {
9
+ throw Error('DankConfig.previewPort must be a number');
10
+ }
11
+ }
2
12
  validatePages(c.pages);
3
13
  validateDevServices(c.services);
14
+ validateEsbuildConfig(c.esbuild);
4
15
  normalizePagePaths(c.pages);
5
16
  return c;
6
17
  }
18
+ function validateEsbuildConfig(esbuild) {
19
+ if (esbuild?.loaders !== null && typeof esbuild?.loaders !== 'undefined') {
20
+ if (typeof esbuild.loaders !== 'object') {
21
+ throw Error('DankConfig.esbuild.loaders must be a map of extensions to esbuild loaders');
22
+ }
23
+ else {
24
+ for (const [ext, loader] of Object.entries(esbuild.loaders)) {
25
+ if (typeof loader !== 'string') {
26
+ throw Error(`DankConfig.esbuild.loaders['${ext}'] must be a string of a loader name`);
27
+ }
28
+ }
29
+ }
30
+ }
31
+ if (esbuild?.plugins !== null && typeof esbuild?.plugins !== 'undefined') {
32
+ if (!Array.isArray(esbuild.plugins)) {
33
+ throw Error('DankConfig.esbuild.plugins must be an array of esbuild plugins');
34
+ }
35
+ }
36
+ if (esbuild?.port !== null && typeof esbuild?.port !== 'undefined') {
37
+ if (typeof esbuild.port !== 'number') {
38
+ throw Error('DankConfig.esbuild.port must be a number');
39
+ }
40
+ }
41
+ }
7
42
  function validatePages(pages) {
8
43
  if (pages === null ||
9
44
  typeof pages === 'undefined' ||
10
45
  Object.keys(pages).length === 0) {
11
46
  throw Error('DankConfig.pages is required');
12
47
  }
13
- for (const [urlPath, htmlPath] of Object.entries(pages)) {
14
- if (typeof htmlPath !== 'string' || !htmlPath.endsWith('.html')) {
15
- throw Error(`DankConfig.pages['${urlPath}'] must configure an html file`);
48
+ for (const [urlPath, mapping] of Object.entries(pages)) {
49
+ if (typeof mapping === 'string' && mapping.endsWith('.html')) {
50
+ continue;
51
+ }
52
+ if (typeof mapping === 'object') {
53
+ validatePageMapping(urlPath, mapping);
54
+ continue;
16
55
  }
56
+ throw Error(`DankConfig.pages['${urlPath}'] must configure an html file`);
17
57
  }
18
58
  }
59
+ function validatePageMapping(urlPath, mapping) {
60
+ if (mapping.webpage === null ||
61
+ typeof mapping.webpage !== 'string' ||
62
+ !mapping.webpage.endsWith('.html')) {
63
+ throw Error(`DankConfig.pages['${urlPath}'].webpage must configure an html file`);
64
+ }
65
+ if (mapping.pattern === null || typeof mapping.pattern === 'undefined') {
66
+ return;
67
+ }
68
+ if (typeof mapping.pattern === 'object' &&
69
+ mapping.pattern.constructor.name === 'RegExp') {
70
+ return;
71
+ }
72
+ throw Error(`DankConfig.pages['${urlPath}'].pattern must be a RegExp`);
73
+ }
19
74
  function validateDevServices(services) {
20
75
  if (services === null || typeof services === 'undefined') {
21
76
  return;
@@ -46,10 +101,23 @@ function validateDevServices(services) {
46
101
  }
47
102
  }
48
103
  }
104
+ if (s.http !== null && typeof s.http !== 'undefined') {
105
+ if (typeof s.http.port !== 'number') {
106
+ throw Error(`DankConfig.services[${i}].http.port must be a number`);
107
+ }
108
+ }
49
109
  }
50
110
  }
51
111
  function normalizePagePaths(pages) {
52
- for (const urlPath of Object.keys(pages)) {
53
- pages[urlPath] = pages[urlPath].replace(/^\.\//, '');
112
+ for (const [pageUrl, mapping] of Object.entries(pages)) {
113
+ if (typeof mapping === 'string') {
114
+ pages[pageUrl] = normalizePagePath(mapping);
115
+ }
116
+ else {
117
+ mapping.webpage = normalizePagePath(mapping.webpage);
118
+ }
54
119
  }
55
120
  }
121
+ function normalizePagePath(p) {
122
+ return p.replace(/^\.\//, '');
123
+ }
package/lib_js/define.js CHANGED
@@ -1,8 +1,6 @@
1
- import { isProductionBuild } from "./flags.js";
2
- export function createGlobalDefinitions() {
3
- const isProduction = isProductionBuild();
1
+ export function createGlobalDefinitions(build) {
4
2
  return {
5
- 'dank.IS_DEV': JSON.stringify(!isProduction),
6
- 'dank.IS_PROD': JSON.stringify(isProduction),
3
+ 'dank.IS_DEV': JSON.stringify(!build.production),
4
+ 'dank.IS_PROD': JSON.stringify(build.production),
7
5
  };
8
6
  }
package/lib_js/esbuild.js CHANGED
@@ -1,50 +1,67 @@
1
+ import { readFile } from 'node:fs/promises';
1
2
  import esbuild, {} from 'esbuild';
2
- import { willMinify } from "./flags.js";
3
- const jsBuildOptions = {
4
- bundle: true,
5
- metafile: true,
6
- minify: willMinify(),
7
- platform: 'browser',
8
- splitting: false,
9
- treeShaking: true,
10
- write: true,
11
- };
12
- const webpageBuildOptions = {
13
- assetNames: 'assets/[name]-[hash]',
14
- format: 'esm',
15
- loader: {
16
- '.tff': 'file',
17
- '.woff': 'file',
18
- '.woff2': 'file',
19
- },
20
- ...jsBuildOptions,
21
- };
22
- export async function esbuildDevContext(define, entryPoints, outdir) {
3
+ export async function esbuildDevContext(b, r, define, entryPoints, c) {
23
4
  return await esbuild.context({
24
5
  define,
25
6
  entryNames: '[dir]/[name]',
26
- entryPoints: removeEntryPointOutExt(entryPoints),
27
- outdir,
28
- ...webpageBuildOptions,
29
- metafile: false,
7
+ entryPoints: mapEntryPointPaths(entryPoints),
8
+ outdir: b.dirs.buildWatch,
9
+ ...commonBuildOptions(b, r, c),
10
+ splitting: false,
30
11
  write: false,
31
12
  });
32
13
  }
33
- export async function esbuildWebpages(define, entryPoints, outdir) {
34
- const buildResult = await esbuild.build({
14
+ export async function esbuildWebpages(b, r, define, entryPoints, c) {
15
+ const result = await esbuild.build({
16
+ define,
17
+ entryNames: '[dir]/[name]-[hash]',
18
+ entryPoints: mapEntryPointPaths(entryPoints),
19
+ outdir: b.dirs.buildDist,
20
+ ...commonBuildOptions(b, r, c),
21
+ });
22
+ esbuildResultChecks(result);
23
+ }
24
+ export async function esbuildWorkers(b, r, define, entryPoints, c) {
25
+ const result = await esbuild.build({
35
26
  define,
36
27
  entryNames: '[dir]/[name]-[hash]',
37
- entryPoints: removeEntryPointOutExt(entryPoints),
38
- outdir,
39
- ...webpageBuildOptions,
28
+ entryPoints: mapEntryPointPaths(entryPoints),
29
+ outdir: b.dirs.buildDist,
30
+ ...commonBuildOptions(b, r, c),
31
+ splitting: false,
32
+ metafile: true,
33
+ write: true,
34
+ assetNames: 'assets/[name]-[hash]',
40
35
  });
41
- esbuildResultChecks(buildResult);
42
- return buildResult.metafile;
36
+ esbuildResultChecks(result);
37
+ }
38
+ function commonBuildOptions(b, r, c) {
39
+ const p = workersPlugin(r.buildRegistry());
40
+ return {
41
+ absWorkingDir: b.dirs.projectRootAbs,
42
+ assetNames: 'assets/[name]-[hash]',
43
+ bundle: true,
44
+ format: 'esm',
45
+ loader: c?.loaders || defaultLoaders(),
46
+ metafile: true,
47
+ minify: b.minify,
48
+ platform: 'browser',
49
+ plugins: c?.plugins?.length ? [p, ...c.plugins] : [p],
50
+ splitting: true,
51
+ treeShaking: true,
52
+ write: true,
53
+ };
54
+ }
55
+ function defaultLoaders() {
56
+ return {
57
+ '.woff': 'file',
58
+ '.woff2': 'file',
59
+ };
43
60
  }
44
61
  // esbuild will append the .js or .css to output filenames
45
62
  // keeping extension on entryPoints data for consistency
46
- // and removing and mapping entryPoints to pass to esbuild
47
- function removeEntryPointOutExt(entryPoints) {
63
+ // and only trimming when creating esbuild opts
64
+ function mapEntryPointPaths(entryPoints) {
48
65
  return entryPoints.map(entryPoint => {
49
66
  return {
50
67
  in: entryPoint.in,
@@ -72,3 +89,91 @@ function esbuildPrintMessage(msg, category) {
72
89
  console.error(' ', note.location);
73
90
  });
74
91
  }
92
+ const WORKER_CTOR_REGEX = /new(?:\s|\r?\n)+Worker(?:\s|\r?\n)*\((?:\s|\r?\n)*(?<url>.*)(?:\s|\r?\n)*\)/g;
93
+ const WORKER_URL_REGEX = /^('.*'|".*")$/;
94
+ export function workersPlugin(r) {
95
+ return {
96
+ name: '@eighty4/dank/esbuild/workers',
97
+ setup(build) {
98
+ if (!build.initialOptions.absWorkingDir)
99
+ throw TypeError('plugin requires absWorkingDir');
100
+ if (!build.initialOptions.metafile)
101
+ throw TypeError('plugin requires metafile');
102
+ const { absWorkingDir } = build.initialOptions;
103
+ build.onLoad({ filter: /\.(t|m?j)s$/ }, async (args) => {
104
+ let contents = await readFile(args.path, 'utf8');
105
+ let offset = 0;
106
+ let errors = undefined;
107
+ for (const workerCtorMatch of contents.matchAll(WORKER_CTOR_REGEX)) {
108
+ const workerUrlString = workerCtorMatch.groups.url;
109
+ if (WORKER_URL_REGEX.test(workerUrlString)) {
110
+ const preamble = contents.substring(0, workerCtorMatch.index);
111
+ const lineIndex = preamble.lastIndexOf('\n') || 0;
112
+ const lineCommented = /\/\//.test(preamble.substring(lineIndex));
113
+ if (lineCommented)
114
+ continue;
115
+ const blockCommentIndex = preamble.lastIndexOf('/*');
116
+ const blockCommented = blockCommentIndex !== -1 &&
117
+ preamble
118
+ .substring(blockCommentIndex)
119
+ .indexOf('*/') === -1;
120
+ if (blockCommented)
121
+ continue;
122
+ const clientScript = args.path
123
+ .replace(absWorkingDir, '')
124
+ .substring(1);
125
+ const workerUrl = workerUrlString.substring(1, workerUrlString.length - 1);
126
+ // todo out of bounds error on path resolve
127
+ const workerEntryPoint = r.resolve(clientScript, workerUrl);
128
+ const workerUrlPlaceholder = workerEntryPoint
129
+ .replace(/^pages/, '')
130
+ .replace(/\.(t|m?j)s$/, '.js');
131
+ const workerCtorReplacement = `new Worker('${workerUrlPlaceholder}')`;
132
+ contents =
133
+ contents.substring(0, workerCtorMatch.index + offset) +
134
+ workerCtorReplacement +
135
+ contents.substring(workerCtorMatch.index +
136
+ workerCtorMatch[0].length +
137
+ offset);
138
+ offset +=
139
+ workerCtorReplacement.length -
140
+ workerCtorMatch[0].length;
141
+ r.addWorker({
142
+ clientScript,
143
+ workerEntryPoint,
144
+ workerUrl,
145
+ workerUrlPlaceholder,
146
+ });
147
+ }
148
+ else {
149
+ if (!errors)
150
+ errors = [];
151
+ const preamble = contents.substring(0, workerCtorMatch.index);
152
+ const line = preamble.match(/\n/g)?.length || 0;
153
+ const lineIndex = preamble.lastIndexOf('\n') || 0;
154
+ const column = preamble.length - lineIndex;
155
+ const lineText = contents.substring(lineIndex, contents.indexOf('\n', lineIndex) ||
156
+ contents.length);
157
+ errors.push({
158
+ id: 'worker-url-unresolvable',
159
+ location: {
160
+ lineText,
161
+ line,
162
+ column,
163
+ file: args.path,
164
+ length: workerCtorMatch[0].length,
165
+ },
166
+ });
167
+ }
168
+ }
169
+ const loader = args.path.endsWith('ts') ? 'ts' : 'js';
170
+ return { contents, errors, loader };
171
+ });
172
+ build.onEnd((result) => {
173
+ if (result.metafile) {
174
+ r.completeBuild(result);
175
+ }
176
+ });
177
+ },
178
+ };
179
+ }
package/lib_js/flags.js CHANGED
@@ -1,11 +1,123 @@
1
+ import { join, resolve } from 'node:path';
2
+ import { cwd } from 'node:process';
3
+ export function resolveBuildFlags() {
4
+ const flags = {
5
+ dirs: defaultProjectDirs(cwd()),
6
+ minify: willMinify(),
7
+ production: isProductionBuild(),
8
+ };
9
+ return {
10
+ get dirs() {
11
+ return flags.dirs;
12
+ },
13
+ get minify() {
14
+ return flags.minify;
15
+ },
16
+ get production() {
17
+ return flags.production;
18
+ },
19
+ };
20
+ }
21
+ export function resolveServeFlags(c) {
22
+ const preview = isPreviewBuild();
23
+ const flags = {
24
+ dirs: defaultProjectDirs(cwd()),
25
+ dankPort: dankPort(c, preview),
26
+ esbuildPort: esbuildPort(c),
27
+ logHttp: willLogHttp(),
28
+ minify: willMinify(),
29
+ preview,
30
+ production: isProductionBuild(),
31
+ };
32
+ return {
33
+ get dirs() {
34
+ return flags.dirs;
35
+ },
36
+ get dankPort() {
37
+ return flags.dankPort;
38
+ },
39
+ get esbuildPort() {
40
+ return flags.esbuildPort;
41
+ },
42
+ get logHttp() {
43
+ return flags.logHttp;
44
+ },
45
+ get minify() {
46
+ return flags.minify;
47
+ },
48
+ get preview() {
49
+ return flags.preview;
50
+ },
51
+ get production() {
52
+ return flags.production;
53
+ },
54
+ };
55
+ }
1
56
  // `dank serve` will pre-bundle and use service worker
2
- export const isPreviewBuild = () => process.env.PREVIEW === 'true' || process.argv.includes('--preview');
57
+ const isPreviewBuild = () => process.env.PREVIEW === 'true' || process.argv.includes('--preview');
3
58
  // `dank build` will minify sources and append git release tag to build tag
4
59
  // `dank serve` will pre-bundle with service worker and minify
5
- export const isProductionBuild = () => process.env.PRODUCTION === 'true' || process.argv.includes('--production');
6
- export const willMinify = () => isProductionBuild() ||
60
+ const isProductionBuild = () => process.env.PRODUCTION === 'true' || process.argv.includes('--production');
61
+ // `dank serve` dank port for frontend webserver
62
+ // alternate --preview port for service worker builds
63
+ function dankPort(c, preview) {
64
+ if (process.env.DANK_PORT?.length) {
65
+ return parsePortEnvVar('DANK_PORT');
66
+ }
67
+ return preview ? c.previewPort || c.port || 4000 : c.port || 3000;
68
+ }
69
+ // `dank serve` esbuild port for bundler integration
70
+ function esbuildPort(c) {
71
+ if (process.env.ESBUILD_PORT?.length) {
72
+ return parsePortEnvVar('ESBUILD_PORT');
73
+ }
74
+ return c.esbuild?.port || 3995;
75
+ }
76
+ function parsePortEnvVar(name) {
77
+ const port = parseInt(process.env[name], 10);
78
+ if (isNaN(port)) {
79
+ throw Error(`env var ${name}=${port} must be a valid port number`);
80
+ }
81
+ else {
82
+ return port;
83
+ }
84
+ }
85
+ export function defaultProjectDirs(projectRootAbs) {
86
+ const dirs = {
87
+ buildRoot: 'build',
88
+ buildDist: join('build', 'dist'),
89
+ buildWatch: join('build', 'watch'),
90
+ pages: 'pages',
91
+ pagesResolved: resolve(join(projectRootAbs, 'pages')),
92
+ projectRootAbs,
93
+ public: 'public',
94
+ };
95
+ return {
96
+ get buildRoot() {
97
+ return dirs.buildRoot;
98
+ },
99
+ get buildDist() {
100
+ return dirs.buildDist;
101
+ },
102
+ get buildWatch() {
103
+ return dirs.buildWatch;
104
+ },
105
+ get pages() {
106
+ return dirs.pages;
107
+ },
108
+ get pagesResolved() {
109
+ return dirs.pagesResolved;
110
+ },
111
+ get projectRootAbs() {
112
+ return dirs.projectRootAbs;
113
+ },
114
+ get public() {
115
+ return dirs.public;
116
+ },
117
+ };
118
+ }
119
+ const willMinify = () => isProductionBuild() ||
7
120
  process.env.MINIFY === 'true' ||
8
121
  process.argv.includes('--minify');
9
- export const willTsc = () => isProductionBuild() ||
10
- process.env.TSC === 'true' ||
11
- process.argv.includes('--tsc');
122
+ // `dank serve` will print http access logs to console
123
+ const willLogHttp = () => process.env.LOG_HTTP === 'true' || process.argv.includes('--log-http');