balm-core 5.2.0 → 6.0.0-alpha.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/dist/index.cjs +2191 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +559 -0
- package/dist/index.d.ts +559 -0
- package/dist/index.js +2098 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -123
- package/src/balm.ts +103 -0
- package/src/bundler/esbuild.ts +47 -0
- package/src/bundler/index.ts +3 -0
- package/src/bundler/rollup.ts +39 -0
- package/src/bundler/webpack.ts +82 -0
- package/src/config/constants.ts +12 -0
- package/src/config/defaults.ts +209 -0
- package/src/config/index.ts +112 -0
- package/src/hooks/index.ts +192 -0
- package/src/index.ts +16 -0
- package/src/pipeline/file.ts +69 -0
- package/src/pipeline/index.ts +10 -0
- package/src/pipeline/pipeline.ts +132 -0
- package/src/pipeline/transforms/cache.ts +96 -0
- package/src/pipeline/transforms/htmlmin.ts +18 -0
- package/src/pipeline/transforms/less.ts +75 -0
- package/src/pipeline/transforms/postcss.ts +43 -0
- package/src/pipeline/transforms/rename.ts +37 -0
- package/src/pipeline/transforms/replace.ts +30 -0
- package/src/pipeline/transforms/sass.ts +106 -0
- package/src/pipeline/transforms/terser.ts +20 -0
- package/src/runner/dag.ts +77 -0
- package/src/runner/task.ts +38 -0
- package/src/shims.d.ts +5 -0
- package/src/tasks/cache.ts +58 -0
- package/src/tasks/clean.ts +21 -0
- package/src/tasks/copy.ts +36 -0
- package/src/tasks/ftp.ts +90 -0
- package/src/tasks/html.ts +78 -0
- package/src/tasks/index.ts +13 -0
- package/src/tasks/publish.ts +71 -0
- package/src/tasks/pwa.ts +49 -0
- package/src/tasks/remove.ts +24 -0
- package/src/tasks/replace.ts +34 -0
- package/src/tasks/script.ts +28 -0
- package/src/tasks/server.ts +89 -0
- package/src/tasks/style.ts +57 -0
- package/src/tasks/zip.ts +65 -0
- package/src/types/index.ts +200 -0
- package/src/utilities/file.ts +120 -0
- package/src/utilities/logger.ts +63 -0
- package/src/utilities/utils.ts +46 -0
- package/src/utilities/workspace.ts +38 -0
- package/src/watcher/index.ts +100 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +12 -0
- package/README.md +0 -196
- package/index.d.ts +0 -360
- package/lib/balm.js +0 -49
- package/lib/bootstrap/check_config.js +0 -43
- package/lib/bootstrap/index.js +0 -87
- package/lib/bundler/esbuild/build.js +0 -26
- package/lib/bundler/esbuild/index.js +0 -7
- package/lib/bundler/esbuild/options.js +0 -7
- package/lib/bundler/esbuild/transform.js +0 -36
- package/lib/bundler/rollup/build.js +0 -52
- package/lib/bundler/rollup/entry.js +0 -28
- package/lib/bundler/rollup/index.js +0 -20
- package/lib/bundler/rollup/output.js +0 -20
- package/lib/bundler/rollup/plugins.js +0 -31
- package/lib/bundler/webpack/config/common.js +0 -135
- package/lib/bundler/webpack/config/dev.js +0 -12
- package/lib/bundler/webpack/config/env.js +0 -67
- package/lib/bundler/webpack/config/index.js +0 -6
- package/lib/bundler/webpack/config/prod.js +0 -39
- package/lib/bundler/webpack/config/regex.js +0 -10
- package/lib/bundler/webpack/entry.js +0 -65
- package/lib/bundler/webpack/index.js +0 -32
- package/lib/bundler/webpack/loaders.js +0 -50
- package/lib/bundler/webpack/output.js +0 -41
- package/lib/bundler/webpack/rules/asset.js +0 -33
- package/lib/bundler/webpack/rules/babel.js +0 -19
- package/lib/bundler/webpack/rules/css.js +0 -109
- package/lib/bundler/webpack/rules/html.js +0 -15
- package/lib/bundler/webpack/rules/index.js +0 -10
- package/lib/config/assets.js +0 -30
- package/lib/config/constants.js +0 -14
- package/lib/config/env.js +0 -35
- package/lib/config/extras.js +0 -6
- package/lib/config/ftp.js +0 -6
- package/lib/config/globals.js +0 -43
- package/lib/config/html.js +0 -22
- package/lib/config/images.js +0 -4
- package/lib/config/index.js +0 -63
- package/lib/config/logs.js +0 -11
- package/lib/config/paths.js +0 -46
- package/lib/config/pwa.js +0 -24
- package/lib/config/roots.js +0 -9
- package/lib/config/scripts.js +0 -162
- package/lib/config/server.js +0 -84
- package/lib/config/spinner.js +0 -9
- package/lib/config/styles.js +0 -67
- package/lib/hello.js +0 -19
- package/lib/hooks/index.js +0 -94
- package/lib/hooks/maker.js +0 -59
- package/lib/index.js +0 -5
- package/lib/middlewares/history.js +0 -6
- package/lib/middlewares/index.js +0 -11
- package/lib/middlewares/proxy.js +0 -28
- package/lib/middlewares/webpack.js +0 -26
- package/lib/plugins/htmlmin.js +0 -39
- package/lib/plugins/imagemin.js +0 -95
- package/lib/plugins/index.js +0 -27
- package/lib/plugins/jsmin.js +0 -37
- package/lib/plugins/less.js +0 -97
- package/lib/plugins/plumber.js +0 -87
- package/lib/plugins/postcss-plugins.js +0 -13
- package/lib/plugins/postcss.js +0 -117
- package/lib/plugins/rename.js +0 -51
- package/lib/plugins/replace.js +0 -91
- package/lib/plugins/sass-legacy.js +0 -131
- package/lib/plugins/sass.js +0 -134
- package/lib/plugins/sftp.js +0 -288
- package/lib/tasks/default.js +0 -46
- package/lib/tasks/foundation/balm.js +0 -72
- package/lib/tasks/foundation/balm_style.js +0 -65
- package/lib/tasks/foundation/index.js +0 -10
- package/lib/tasks/index.js +0 -48
- package/lib/tasks/private/build.js +0 -18
- package/lib/tasks/private/cache.js +0 -31
- package/lib/tasks/private/clean.js +0 -69
- package/lib/tasks/private/end.js +0 -24
- package/lib/tasks/private/extra.js +0 -35
- package/lib/tasks/private/font.js +0 -15
- package/lib/tasks/private/image.js +0 -37
- package/lib/tasks/private/index.js +0 -34
- package/lib/tasks/private/lint.js +0 -20
- package/lib/tasks/private/media.js +0 -15
- package/lib/tasks/private/modernizr.js +0 -59
- package/lib/tasks/private/pwa-cache.js +0 -32
- package/lib/tasks/private/script.js +0 -9
- package/lib/tasks/private/sprite.js +0 -105
- package/lib/tasks/private/start.js +0 -16
- package/lib/tasks/private/style.js +0 -9
- package/lib/tasks/private/workbox-sw.js +0 -15
- package/lib/tasks/public/copy.js +0 -16
- package/lib/tasks/public/esbuild.js +0 -18
- package/lib/tasks/public/ftp.js +0 -39
- package/lib/tasks/public/html.js +0 -65
- package/lib/tasks/public/index.js +0 -38
- package/lib/tasks/public/jsmin.js +0 -23
- package/lib/tasks/public/less.js +0 -21
- package/lib/tasks/public/postcss.js +0 -16
- package/lib/tasks/public/publish.js +0 -51
- package/lib/tasks/public/pwa.js +0 -84
- package/lib/tasks/public/remove.js +0 -46
- package/lib/tasks/public/replace.js +0 -26
- package/lib/tasks/public/rollup.js +0 -17
- package/lib/tasks/public/sass.js +0 -27
- package/lib/tasks/public/server.js +0 -130
- package/lib/tasks/public/url.js +0 -35
- package/lib/tasks/public/version.js +0 -23
- package/lib/tasks/public/webpack.js +0 -39
- package/lib/tasks/public/zip.js +0 -19
- package/lib/utilities/address.js +0 -55
- package/lib/utilities/cache-core.js +0 -66
- package/lib/utilities/color.js +0 -27
- package/lib/utilities/compiling.js +0 -24
- package/lib/utilities/detect-port.js +0 -100
- package/lib/utilities/escape-string-regexp.js +0 -10
- package/lib/utilities/file.js +0 -70
- package/lib/utilities/index.js +0 -8
- package/lib/utilities/loading.js +0 -37
- package/lib/utilities/logger.js +0 -99
- package/lib/utilities/merge-stream.js +0 -38
- package/lib/utilities/namespace.js +0 -11
- package/lib/utilities/public-url.js +0 -37
- package/lib/utilities/replacestream.js +0 -106
- package/lib/utilities/typeof.js +0 -5
- package/lib/utilities/utils.js +0 -43
- package/tslib/balm.js +0 -44
- package/tslib/bootstrap/check_config.js +0 -36
- package/tslib/bootstrap/index.js +0 -82
- package/tslib/bundler/esbuild/build.js +0 -30
- package/tslib/bundler/esbuild/index.js +0 -11
- package/tslib/bundler/esbuild/options.js +0 -7
- package/tslib/bundler/esbuild/transform.js +0 -38
- package/tslib/bundler/rollup/build.js +0 -17
- package/tslib/bundler/rollup/entry.js +0 -24
- package/tslib/bundler/rollup/index.js +0 -21
- package/tslib/bundler/rollup/output.js +0 -23
- package/tslib/bundler/rollup/plugins.js +0 -27
- package/tslib/bundler/webpack/config/common.js +0 -130
- package/tslib/bundler/webpack/config/dev.js +0 -14
- package/tslib/bundler/webpack/config/env.js +0 -44
- package/tslib/bundler/webpack/config/index.js +0 -8
- package/tslib/bundler/webpack/config/prod.js +0 -43
- package/tslib/bundler/webpack/config/regex.js +0 -10
- package/tslib/bundler/webpack/entry.js +0 -68
- package/tslib/bundler/webpack/index.js +0 -30
- package/tslib/bundler/webpack/loaders.js +0 -51
- package/tslib/bundler/webpack/output.js +0 -41
- package/tslib/bundler/webpack/rules/asset.js +0 -33
- package/tslib/bundler/webpack/rules/babel.js +0 -16
- package/tslib/bundler/webpack/rules/css.js +0 -95
- package/tslib/bundler/webpack/rules/html.js +0 -15
- package/tslib/bundler/webpack/rules/index.js +0 -10
- package/tslib/config/assets.js +0 -24
- package/tslib/config/constants.js +0 -14
- package/tslib/config/env.js +0 -43
- package/tslib/config/extras.js +0 -6
- package/tslib/config/ftp.js +0 -6
- package/tslib/config/globals.js +0 -47
- package/tslib/config/html.js +0 -17
- package/tslib/config/images.js +0 -4
- package/tslib/config/index.js +0 -56
- package/tslib/config/logs.js +0 -6
- package/tslib/config/paths.js +0 -30
- package/tslib/config/pwa.js +0 -18
- package/tslib/config/roots.js +0 -8
- package/tslib/config/scripts.js +0 -93
- package/tslib/config/server.js +0 -33
- package/tslib/config/spinner.js +0 -10
- package/tslib/config/styles.js +0 -37
- package/tslib/hello.js +0 -19
- package/tslib/hooks/index.js +0 -75
- package/tslib/hooks/maker.js +0 -66
- package/tslib/index.js +0 -5
- package/tslib/middlewares/history.js +0 -12
- package/tslib/middlewares/index.js +0 -18
- package/tslib/middlewares/proxy.js +0 -27
- package/tslib/middlewares/webpack.js +0 -29
- package/tslib/plugins/htmlmin.js +0 -38
- package/tslib/plugins/imagemin.js +0 -97
- package/tslib/plugins/index.js +0 -27
- package/tslib/plugins/jsmin.js +0 -39
- package/tslib/plugins/less.js +0 -90
- package/tslib/plugins/plumber.js +0 -81
- package/tslib/plugins/postcss-plugins.js +0 -24
- package/tslib/plugins/postcss.js +0 -111
- package/tslib/plugins/rename.js +0 -51
- package/tslib/plugins/replace.js +0 -72
- package/tslib/plugins/sass-legacy.js +0 -95
- package/tslib/plugins/sass.js +0 -109
- package/tslib/plugins/sftp.js +0 -258
- package/tslib/tasks/default.js +0 -59
- package/tslib/tasks/foundation/balm.js +0 -75
- package/tslib/tasks/foundation/balm_style.js +0 -68
- package/tslib/tasks/foundation/index.js +0 -10
- package/tslib/tasks/index.js +0 -43
- package/tslib/tasks/private/build.js +0 -15
- package/tslib/tasks/private/cache.js +0 -48
- package/tslib/tasks/private/clean.js +0 -82
- package/tslib/tasks/private/end.js +0 -21
- package/tslib/tasks/private/extra.js +0 -34
- package/tslib/tasks/private/font.js +0 -12
- package/tslib/tasks/private/image.js +0 -42
- package/tslib/tasks/private/index.js +0 -34
- package/tslib/tasks/private/lint.js +0 -17
- package/tslib/tasks/private/media.js +0 -12
- package/tslib/tasks/private/modernizr.js +0 -54
- package/tslib/tasks/private/pwa-cache.js +0 -32
- package/tslib/tasks/private/script.js +0 -9
- package/tslib/tasks/private/sprite.js +0 -93
- package/tslib/tasks/private/start.js +0 -13
- package/tslib/tasks/private/style.js +0 -12
- package/tslib/tasks/private/workbox-sw.js +0 -15
- package/tslib/tasks/public/copy.js +0 -18
- package/tslib/tasks/public/esbuild.js +0 -18
- package/tslib/tasks/public/ftp.js +0 -39
- package/tslib/tasks/public/html.js +0 -75
- package/tslib/tasks/public/index.js +0 -38
- package/tslib/tasks/public/jsmin.js +0 -24
- package/tslib/tasks/public/less.js +0 -21
- package/tslib/tasks/public/postcss.js +0 -16
- package/tslib/tasks/public/publish.js +0 -50
- package/tslib/tasks/public/pwa.js +0 -87
- package/tslib/tasks/public/remove.js +0 -44
- package/tslib/tasks/public/replace.js +0 -27
- package/tslib/tasks/public/rollup.js +0 -17
- package/tslib/tasks/public/sass.js +0 -27
- package/tslib/tasks/public/server.js +0 -129
- package/tslib/tasks/public/url.js +0 -35
- package/tslib/tasks/public/version.js +0 -27
- package/tslib/tasks/public/webpack.js +0 -41
- package/tslib/tasks/public/zip.js +0 -19
- package/tslib/utilities/address.js +0 -48
- package/tslib/utilities/cache-core.js +0 -57
- package/tslib/utilities/color.js +0 -33
- package/tslib/utilities/compiling.js +0 -16
- package/tslib/utilities/detect-port.js +0 -91
- package/tslib/utilities/escape-string-regexp.js +0 -7
- package/tslib/utilities/file.js +0 -78
- package/tslib/utilities/index.js +0 -8
- package/tslib/utilities/loading.js +0 -25
- package/tslib/utilities/logger.js +0 -92
- package/tslib/utilities/merge-stream.js +0 -34
- package/tslib/utilities/namespace.js +0 -12
- package/tslib/utilities/public-url.js +0 -31
- package/tslib/utilities/replacestream.js +0 -112
- package/tslib/utilities/typeof.js +0 -8
- package/tslib/utilities/utils.js +0 -38
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BaseTask } from './task.js';
|
|
2
|
+
import { BalmConfig } from '../types/index.js';
|
|
3
|
+
import { logger } from '../utilities/logger.js';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
|
|
6
|
+
export class TaskDAG {
|
|
7
|
+
private tasks = new Map<string, BaseTask>();
|
|
8
|
+
|
|
9
|
+
registerTask(task: BaseTask): void {
|
|
10
|
+
this.tasks.set(task.name, task);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getTask(name: string): BaseTask | undefined {
|
|
14
|
+
return this.tasks.get(name);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
hasTask(name: string): boolean {
|
|
18
|
+
return this.tasks.has(name);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
clear(): void {
|
|
22
|
+
this.tasks.clear();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Run a list of tasks in strict series
|
|
27
|
+
*/
|
|
28
|
+
async runSeries(taskNames: string[], config: BalmConfig): Promise<void> {
|
|
29
|
+
for (const name of taskNames) {
|
|
30
|
+
await this.executeTask(name, config);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Run a list of tasks in parallel
|
|
36
|
+
*/
|
|
37
|
+
async runParallel(taskNames: string[], config: BalmConfig): Promise<void> {
|
|
38
|
+
await Promise.all(taskNames.map((name) => this.executeTask(name, config)));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Execute a single task resolving its dependencies first
|
|
43
|
+
*/
|
|
44
|
+
async executeTask(
|
|
45
|
+
taskName: string,
|
|
46
|
+
config: BalmConfig,
|
|
47
|
+
executed = new Set<string>()
|
|
48
|
+
): Promise<void> {
|
|
49
|
+
if (executed.has(taskName)) return;
|
|
50
|
+
|
|
51
|
+
const task = this.tasks.get(taskName);
|
|
52
|
+
if (!task) {
|
|
53
|
+
logger.warn('task', `Task ${pc.bold(taskName)} not found, skipping.`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Execute dependencies first
|
|
58
|
+
if (task.deps && task.deps.length > 0) {
|
|
59
|
+
for (const dep of task.deps) {
|
|
60
|
+
await this.executeTask(dep, config, executed);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const start = performance.now();
|
|
65
|
+
try {
|
|
66
|
+
await task.run(config);
|
|
67
|
+
executed.add(taskName);
|
|
68
|
+
const duration = (performance.now() - start).toFixed(1);
|
|
69
|
+
if (!task.hidden) {
|
|
70
|
+
logger.info('task', `${pc.cyan(task.name)} finished in ${pc.bold(duration + 'ms')}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (error: any) {
|
|
73
|
+
logger.error('task', `Task ${pc.bold(task.name)} failed: ${error?.message || error}`);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BalmConfig } from '../types/index.js';
|
|
2
|
+
import { logger } from '../utilities/logger.js';
|
|
3
|
+
|
|
4
|
+
export interface TaskOptions {
|
|
5
|
+
name: string;
|
|
6
|
+
deps?: string[];
|
|
7
|
+
description?: string;
|
|
8
|
+
hidden?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export abstract class BaseTask {
|
|
12
|
+
name: string;
|
|
13
|
+
deps: string[];
|
|
14
|
+
description?: string;
|
|
15
|
+
hidden: boolean;
|
|
16
|
+
|
|
17
|
+
constructor(options: TaskOptions) {
|
|
18
|
+
this.name = options.name;
|
|
19
|
+
this.deps = options.deps || [];
|
|
20
|
+
this.description = options.description;
|
|
21
|
+
this.hidden = options.hidden || false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
abstract run(config: BalmConfig): Promise<void> | void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class FunctionTask extends BaseTask {
|
|
28
|
+
private fn: (config: BalmConfig) => Promise<void> | void;
|
|
29
|
+
|
|
30
|
+
constructor(name: string, fn: (config: BalmConfig) => Promise<void> | void, deps: string[] = []) {
|
|
31
|
+
super({ name, deps });
|
|
32
|
+
this.fn = fn;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async run(config: BalmConfig): Promise<void> {
|
|
36
|
+
await this.fn(config);
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/shims.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fg from 'fast-glob';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import { BaseTask } from '../runner/task.js';
|
|
5
|
+
import { BalmConfig } from '../types/index.js';
|
|
6
|
+
import { VirtualFile } from '../pipeline/file.js';
|
|
7
|
+
import { AssetRevisioner } from '../pipeline/transforms/cache.js';
|
|
8
|
+
import { file as fsUtil } from '../utilities/file.js';
|
|
9
|
+
import { logger } from '../utilities/logger.js';
|
|
10
|
+
|
|
11
|
+
export class CacheTask extends BaseTask {
|
|
12
|
+
constructor() {
|
|
13
|
+
super({ name: 'cache', description: 'Revision assets and generate manifest' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async run(config: BalmConfig): Promise<void> {
|
|
17
|
+
const destDir = config.dest.base;
|
|
18
|
+
const filesToRev = await fg(['**/*'], {
|
|
19
|
+
cwd: destDir,
|
|
20
|
+
absolute: true,
|
|
21
|
+
onlyFiles: true
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (!filesToRev.length) {
|
|
25
|
+
logger.warn('cache', 'No files found to cache');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const virtualFiles = await Promise.all(
|
|
30
|
+
filesToRev.map(async (filePath) => {
|
|
31
|
+
const buffer = await fs.readFile(filePath);
|
|
32
|
+
return new VirtualFile({
|
|
33
|
+
cwd: config.workspace,
|
|
34
|
+
base: destDir,
|
|
35
|
+
path: filePath,
|
|
36
|
+
contents: buffer
|
|
37
|
+
});
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const revisioner = new AssetRevisioner(config.assets.options);
|
|
42
|
+
const resultFiles = revisioner.process(virtualFiles);
|
|
43
|
+
|
|
44
|
+
// Remove old files that have been renamed
|
|
45
|
+
for (const vFile of resultFiles) {
|
|
46
|
+
if (vFile.revPathOriginal && vFile.revPathOriginal !== vFile.path) {
|
|
47
|
+
await fsUtil.remove(vFile.revPathOriginal);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Write new / updated files
|
|
52
|
+
for (const vFile of resultFiles) {
|
|
53
|
+
await fsUtil.writeFile(vFile.path, vFile.contents);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
logger.success('cache', 'Asset revisioning and rev-manifest.json completed');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig } from '../types/index.js';
|
|
4
|
+
import { file } from '../utilities/file.js';
|
|
5
|
+
import { logger } from '../utilities/logger.js';
|
|
6
|
+
|
|
7
|
+
export class CleanTask extends BaseTask {
|
|
8
|
+
constructor() {
|
|
9
|
+
super({ name: 'clean', description: 'Clean output directories' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run(config: BalmConfig): Promise<void> {
|
|
13
|
+
const targets = [
|
|
14
|
+
path.join(config.workspace, config.roots.tmp),
|
|
15
|
+
path.join(config.workspace, config.roots.target)
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const deleted = await file.remove(targets);
|
|
19
|
+
logger.info('clean', `Deleted ${deleted.length} directories`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig, RenameOptions } from '../types/index.js';
|
|
4
|
+
import { Pipeline } from '../pipeline/pipeline.js';
|
|
5
|
+
import { transformRename } from '../pipeline/transforms/rename.js';
|
|
6
|
+
|
|
7
|
+
export interface CopyTaskOptions {
|
|
8
|
+
input: string | string[];
|
|
9
|
+
output: string;
|
|
10
|
+
rename?: RenameOptions | string | Function;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class CopyTask extends BaseTask {
|
|
14
|
+
private options: CopyTaskOptions;
|
|
15
|
+
|
|
16
|
+
constructor(options: CopyTaskOptions) {
|
|
17
|
+
super({ name: 'copy', description: 'Copy files to destination' });
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run(config: BalmConfig): Promise<void> {
|
|
22
|
+
const pipeline = Pipeline.from(this.options.input, {
|
|
23
|
+
cwd: config.workspace
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (this.options.rename) {
|
|
27
|
+
pipeline.pipe(transformRename(this.options.rename));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const outDir = path.isAbsolute(this.options.output)
|
|
31
|
+
? this.options.output
|
|
32
|
+
: path.join(config.workspace, this.options.output);
|
|
33
|
+
|
|
34
|
+
await pipeline.dest(outDir);
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/tasks/ftp.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { Client } from 'ssh2';
|
|
4
|
+
import fg from 'fast-glob';
|
|
5
|
+
import { BaseTask } from '../runner/task.js';
|
|
6
|
+
import { BalmConfig } from '../types/index.js';
|
|
7
|
+
import { logger } from '../utilities/logger.js';
|
|
8
|
+
|
|
9
|
+
export interface FtpTaskOptions {
|
|
10
|
+
localFiles?: string | string[];
|
|
11
|
+
options?: {
|
|
12
|
+
host?: string;
|
|
13
|
+
port?: number;
|
|
14
|
+
username?: string;
|
|
15
|
+
password?: string;
|
|
16
|
+
privateKey?: string;
|
|
17
|
+
remotePath?: string;
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class FtpTask extends BaseTask {
|
|
23
|
+
private ftpOptions: FtpTaskOptions;
|
|
24
|
+
|
|
25
|
+
constructor(ftpOptions: FtpTaskOptions = {}) {
|
|
26
|
+
super({ name: 'ftp', description: 'Upload files via SFTP' });
|
|
27
|
+
this.ftpOptions = ftpOptions;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async run(config: BalmConfig): Promise<void> {
|
|
31
|
+
const options = {
|
|
32
|
+
port: 22,
|
|
33
|
+
remotePath: '/',
|
|
34
|
+
...config.ftp.options,
|
|
35
|
+
...this.ftpOptions.options
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (!options.host) {
|
|
39
|
+
logger.error('ftp', '`host` required for SFTP');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const localFiles = this.ftpOptions.localFiles || config.dest.base;
|
|
44
|
+
const files = await fg(localFiles, { cwd: config.workspace, absolute: true, onlyFiles: true });
|
|
45
|
+
|
|
46
|
+
if (!files.length) {
|
|
47
|
+
logger.warn('ftp', 'No files to upload');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const conn = new Client();
|
|
53
|
+
|
|
54
|
+
conn.on('ready', () => {
|
|
55
|
+
conn.sftp((err, sftp) => {
|
|
56
|
+
if (err) {
|
|
57
|
+
conn.end();
|
|
58
|
+
return reject(err);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let pending = files.length;
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
const rel = path.relative(config.workspace, file);
|
|
64
|
+
const remoteFile = path.posix.join(options.remotePath, rel);
|
|
65
|
+
|
|
66
|
+
sftp.fastPut(file, remoteFile, (putErr) => {
|
|
67
|
+
if (putErr) {
|
|
68
|
+
logger.error('ftp', `Failed uploading ${file}: ${putErr.message}`);
|
|
69
|
+
} else {
|
|
70
|
+
logger.info('ftp', `Uploaded ${file} -> ${remoteFile}`);
|
|
71
|
+
}
|
|
72
|
+
pending--;
|
|
73
|
+
if (pending === 0) {
|
|
74
|
+
conn.end();
|
|
75
|
+
resolve();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
conn.on('error', (connErr) => {
|
|
83
|
+
logger.error('ftp', connErr.message);
|
|
84
|
+
reject(connErr);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
conn.connect(options as any);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig } from '../types/index.js';
|
|
4
|
+
import { Pipeline } from '../pipeline/pipeline.js';
|
|
5
|
+
import { transformHtmlmin } from '../pipeline/transforms/htmlmin.js';
|
|
6
|
+
import { transformReplace } from '../pipeline/transforms/replace.js';
|
|
7
|
+
import { PUBLIC_URL } from '../config/constants.js';
|
|
8
|
+
|
|
9
|
+
const LIVE_RELOAD_SCRIPT = `
|
|
10
|
+
<!-- BalmJS Live Reload -->
|
|
11
|
+
<script>
|
|
12
|
+
(() => {
|
|
13
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
14
|
+
const ws = new WebSocket(\`\${protocol}//\${location.host}/__balm_ws\`);
|
|
15
|
+
ws.onmessage = (e) => {
|
|
16
|
+
try {
|
|
17
|
+
const msg = JSON.parse(e.data);
|
|
18
|
+
if (msg.type === 'reload') {
|
|
19
|
+
console.log('[BalmJS] Reloading page...');
|
|
20
|
+
location.reload();
|
|
21
|
+
} else if (msg.type === 'reload-css') {
|
|
22
|
+
console.log('[BalmJS] Reloading CSS...');
|
|
23
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
24
|
+
for (const link of links) {
|
|
25
|
+
const url = new URL(link.href);
|
|
26
|
+
url.searchParams.set('_balm_t', Date.now().toString());
|
|
27
|
+
link.href = url.href;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} catch {}
|
|
31
|
+
};
|
|
32
|
+
ws.onclose = () => {
|
|
33
|
+
setTimeout(() => location.reload(), 2000);
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
</script>
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
export class HtmlTask extends BaseTask {
|
|
40
|
+
constructor() {
|
|
41
|
+
super({ name: 'html', description: 'Process HTML templates' });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async run(config: BalmConfig): Promise<void> {
|
|
45
|
+
const templateDir = config.scripts.injectHtml
|
|
46
|
+
? config.src.base
|
|
47
|
+
: config.src.html;
|
|
48
|
+
|
|
49
|
+
const pattern = path.join(templateDir, '*.html');
|
|
50
|
+
const pipeline = Pipeline.from(pattern, {
|
|
51
|
+
cwd: config.workspace,
|
|
52
|
+
base: templateDir
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Replace %PUBLIC_URL% placeholder
|
|
56
|
+
const publicUrlReplacement = config.assets.virtualDir ? `/${config.assets.virtualDir}` : '';
|
|
57
|
+
pipeline.pipe(transformReplace(new RegExp(PUBLIC_URL, 'g'), publicUrlReplacement));
|
|
58
|
+
|
|
59
|
+
if (config.env.isProd) {
|
|
60
|
+
pipeline.pipe(transformHtmlmin(config.html.options));
|
|
61
|
+
} else {
|
|
62
|
+
pipeline.pipe(async (file) => {
|
|
63
|
+
if (/\.html$/i.test(file.extname)) {
|
|
64
|
+
let content = file.toString();
|
|
65
|
+
if (content.includes('</body>')) {
|
|
66
|
+
content = content.replace('</body>', `${LIVE_RELOAD_SCRIPT}\n</body>`);
|
|
67
|
+
} else {
|
|
68
|
+
content += `\n${LIVE_RELOAD_SCRIPT}`;
|
|
69
|
+
}
|
|
70
|
+
file.contents = Buffer.from(content);
|
|
71
|
+
}
|
|
72
|
+
return file;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await pipeline.dest(config.dest.html);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './clean.js';
|
|
2
|
+
export * from './style.js';
|
|
3
|
+
export * from './script.js';
|
|
4
|
+
export * from './html.js';
|
|
5
|
+
export * from './copy.js';
|
|
6
|
+
export * from './remove.js';
|
|
7
|
+
export * from './replace.js';
|
|
8
|
+
export * from './cache.js';
|
|
9
|
+
export * from './publish.js';
|
|
10
|
+
export * from './pwa.js';
|
|
11
|
+
export * from './zip.js';
|
|
12
|
+
export * from './ftp.js';
|
|
13
|
+
export * from './server.js';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig, TemplateOption, RenameOptions } from '../types/index.js';
|
|
4
|
+
import { Pipeline } from '../pipeline/pipeline.js';
|
|
5
|
+
import { transformRename } from '../pipeline/transforms/rename.js';
|
|
6
|
+
import { logger } from '../utilities/logger.js';
|
|
7
|
+
|
|
8
|
+
export interface PublishTaskOptions {
|
|
9
|
+
input?: string | TemplateOption[];
|
|
10
|
+
output?: string;
|
|
11
|
+
renameOptions?: string | Function | RenameOptions;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class PublishTask extends BaseTask {
|
|
15
|
+
private options: PublishTaskOptions;
|
|
16
|
+
|
|
17
|
+
constructor(options: PublishTaskOptions = {}) {
|
|
18
|
+
super({ name: 'publish', description: 'Publish assets or templates' });
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async run(config: BalmConfig): Promise<void> {
|
|
23
|
+
if (!config.env.isProd) {
|
|
24
|
+
logger.warn('publish', '`mix.publish()` is only supported in production mode');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { input, output, renameOptions } = this.options;
|
|
29
|
+
|
|
30
|
+
if (Array.isArray(input)) {
|
|
31
|
+
for (const item of input) {
|
|
32
|
+
await this.publishItem(config, item.input, item.output, item.renameOptions);
|
|
33
|
+
}
|
|
34
|
+
} else if (typeof input === 'string' && output) {
|
|
35
|
+
await this.publishItem(config, input, output, renameOptions);
|
|
36
|
+
} else {
|
|
37
|
+
// Default: publish all static assets from dest.base to assets.static
|
|
38
|
+
const srcDir = config.dest.base;
|
|
39
|
+
const targetDir = config.assets.static || path.join(config.assets.root, config.assets.mainDir);
|
|
40
|
+
|
|
41
|
+
const pipeline = Pipeline.from(['**/*'], {
|
|
42
|
+
cwd: srcDir,
|
|
43
|
+
base: srcDir
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await pipeline.dest(path.resolve(config.workspace, targetDir));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async publishItem(
|
|
51
|
+
config: BalmConfig,
|
|
52
|
+
input: string,
|
|
53
|
+
output: string,
|
|
54
|
+
rename?: string | Function | RenameOptions
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
const srcPath = path.isAbsolute(input) ? input : path.join(config.dest.base, input);
|
|
57
|
+
const destDir = path.isAbsolute(output)
|
|
58
|
+
? output
|
|
59
|
+
: path.join(config.workspace, config.assets.root, output);
|
|
60
|
+
|
|
61
|
+
const pipeline = Pipeline.from(srcPath, {
|
|
62
|
+
cwd: config.dest.base
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (rename) {
|
|
66
|
+
pipeline.pipe(transformRename(rename));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await pipeline.dest(destDir);
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/tasks/pwa.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { generateSW, injectManifest } from 'workbox-build';
|
|
3
|
+
import { BaseTask } from '../runner/task.js';
|
|
4
|
+
import { BalmConfig } from '../types/index.js';
|
|
5
|
+
import { logger } from '../utilities/logger.js';
|
|
6
|
+
|
|
7
|
+
export interface PwaTaskOptions {
|
|
8
|
+
mode?: 'generateSW' | 'injectManifest';
|
|
9
|
+
options?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class PwaTask extends BaseTask {
|
|
13
|
+
private options: PwaTaskOptions;
|
|
14
|
+
|
|
15
|
+
constructor(options: PwaTaskOptions = {}) {
|
|
16
|
+
super({ name: 'pwa', description: 'Generate Progressive Web App Service Worker' });
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async run(config: BalmConfig): Promise<void> {
|
|
21
|
+
const mode = this.options.mode || config.pwa.mode || 'generateSW';
|
|
22
|
+
const globDirectory = config.dest.base;
|
|
23
|
+
const swDest = path.join(globDirectory, config.pwa.swDestFilename);
|
|
24
|
+
const swSrc = path.join(config.src.base, config.pwa.swSrcFilename);
|
|
25
|
+
|
|
26
|
+
const mergedOptions: any = {
|
|
27
|
+
globDirectory,
|
|
28
|
+
swDest,
|
|
29
|
+
...config.pwa.options,
|
|
30
|
+
...this.options.options
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (mode === 'injectManifest') {
|
|
34
|
+
mergedOptions.swSrc = mergedOptions.swSrc || swSrc;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
if (mode === 'generateSW') {
|
|
39
|
+
const { count, size } = await generateSW(mergedOptions);
|
|
40
|
+
logger.info('pwa', `Generated '${swDest}', precaching ${count} files (${size} bytes)`);
|
|
41
|
+
} else {
|
|
42
|
+
const { count, size } = await injectManifest(mergedOptions);
|
|
43
|
+
logger.info('pwa', `Injected manifest into '${swDest}', precaching ${count} files (${size} bytes)`);
|
|
44
|
+
}
|
|
45
|
+
} catch (err: any) {
|
|
46
|
+
logger.warn('pwa', `Service worker generation failed: ${err.message || err}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig } from '../types/index.js';
|
|
4
|
+
import { file } from '../utilities/file.js';
|
|
5
|
+
import { logger } from '../utilities/logger.js';
|
|
6
|
+
|
|
7
|
+
export class RemoveTask extends BaseTask {
|
|
8
|
+
private target: string | string[];
|
|
9
|
+
|
|
10
|
+
constructor(target: string | string[]) {
|
|
11
|
+
super({ name: 'remove', description: 'Remove files and directories' });
|
|
12
|
+
this.target = target;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async run(config: BalmConfig): Promise<void> {
|
|
16
|
+
const targets = Array.isArray(this.target) ? this.target : [this.target];
|
|
17
|
+
const resolvedTargets = targets.map((t) =>
|
|
18
|
+
path.isAbsolute(t) ? t : path.join(config.workspace, t)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const deleted = await file.remove(resolvedTargets);
|
|
22
|
+
logger.warn('remove', `Removed: ${deleted.join(', ')}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BaseTask } from '../runner/task.js';
|
|
3
|
+
import { BalmConfig, ReplaceOptions } from '../types/index.js';
|
|
4
|
+
import { Pipeline } from '../pipeline/pipeline.js';
|
|
5
|
+
import { transformReplace } from '../pipeline/transforms/replace.js';
|
|
6
|
+
|
|
7
|
+
export interface ReplaceTaskOptions {
|
|
8
|
+
input: string | string[];
|
|
9
|
+
output: string;
|
|
10
|
+
options: ReplaceOptions | ReplaceOptions[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class ReplaceTask extends BaseTask {
|
|
14
|
+
private taskOptions: ReplaceTaskOptions;
|
|
15
|
+
|
|
16
|
+
constructor(taskOptions: ReplaceTaskOptions) {
|
|
17
|
+
super({ name: 'replace', description: 'Replace content in files' });
|
|
18
|
+
this.taskOptions = taskOptions;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run(config: BalmConfig): Promise<void> {
|
|
22
|
+
const pipeline = Pipeline.from(this.taskOptions.input, {
|
|
23
|
+
cwd: config.workspace
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
pipeline.pipe(transformReplace(this.taskOptions.options));
|
|
27
|
+
|
|
28
|
+
const outDir = path.isAbsolute(this.taskOptions.output)
|
|
29
|
+
? this.taskOptions.output
|
|
30
|
+
: path.join(config.workspace, this.taskOptions.output);
|
|
31
|
+
|
|
32
|
+
await pipeline.dest(outDir);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BaseTask } from '../runner/task.js';
|
|
2
|
+
import { BalmConfig, BundlerType } from '../types/index.js';
|
|
3
|
+
import { runWebpack } from '../bundler/webpack.js';
|
|
4
|
+
import { runRollup } from '../bundler/rollup.js';
|
|
5
|
+
import { runEsbuild } from '../bundler/esbuild.js';
|
|
6
|
+
|
|
7
|
+
export class ScriptTask extends BaseTask {
|
|
8
|
+
constructor() {
|
|
9
|
+
super({ name: 'script', description: 'Bundle JavaScript/TypeScript' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run(config: BalmConfig): Promise<void> {
|
|
13
|
+
const bundler = config.scripts.bundler;
|
|
14
|
+
|
|
15
|
+
switch (bundler) {
|
|
16
|
+
case BundlerType.rollup:
|
|
17
|
+
await runRollup(config);
|
|
18
|
+
break;
|
|
19
|
+
case BundlerType.esbuild:
|
|
20
|
+
await runEsbuild(config);
|
|
21
|
+
break;
|
|
22
|
+
case BundlerType.webpack:
|
|
23
|
+
default:
|
|
24
|
+
await runWebpack(config);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|