@pictogrammers/element-esbuild 0.0.13 → 0.0.15
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/README.md +7 -0
- package/bin/element-build.js +10 -502
- package/bin/element-publish.js +0 -2
- package/bin/element-start.js +10 -2276
- package/package.json +2 -2
- package/scripts/element-build.ts +20 -1
- package/scripts/element-start.ts +59 -3
- package/scripts/getDirectories.ts +0 -1
- package/scripts/htmlDependentsPlugin.ts +56 -35
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pictogrammers/element-esbuild",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Element esbuild",
|
|
6
6
|
"homepage": "https://github.com/Pictogrammers/Element-esbuild#readme",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"prepublishOnly": "npm run build",
|
|
24
|
-
"build": "esbuild scripts/element-start.ts scripts/element-build.ts scripts/element-publish.ts --bundle --outdir=bin --format=esm --target=esnext --platform=node --external:esbuild --banner:js=\"import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);\""
|
|
24
|
+
"build": "esbuild scripts/element-start.ts scripts/element-build.ts scripts/element-publish.ts --bundle --minify --outdir=bin --format=esm --target=esnext --platform=node --external:esbuild --banner:js=\"import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);\""
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.0.3",
|
package/scripts/element-build.ts
CHANGED
|
@@ -10,13 +10,15 @@ import { copyFile, writeFile } from 'node:fs/promises';
|
|
|
10
10
|
import { dirname, join } from 'node:path';
|
|
11
11
|
import { playgroundPlugin } from './playgroundPlugin.ts';
|
|
12
12
|
import { createPlaygroundIndex } from './createPlaygroundIndex.ts';
|
|
13
|
+
import { getDirectories } from './getDirectories.ts';
|
|
13
14
|
|
|
14
|
-
const plugins = [
|
|
15
|
+
const plugins = [rebuildNotifyPlugin];
|
|
15
16
|
const entryPoints: string[] = [];
|
|
16
17
|
|
|
17
18
|
const green = (text: string) => `\x1b[32m${text}\x1b[0m`;
|
|
18
19
|
const red = (text: string) => `\x1b[31m${text}\x1b[0m`;
|
|
19
20
|
|
|
21
|
+
const nodeModulesDir = 'node_modules';
|
|
20
22
|
const playgroundFile = 'playground.html';
|
|
21
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
22
24
|
const __dirname = dirname(__filename);
|
|
@@ -44,11 +46,28 @@ const {
|
|
|
44
46
|
repo,
|
|
45
47
|
repoComponent,
|
|
46
48
|
navigation,
|
|
49
|
+
external,
|
|
47
50
|
} = config.default;
|
|
48
51
|
|
|
49
52
|
if (namespace) {
|
|
50
53
|
console.log(green('Building app...'));
|
|
51
54
|
entryPoints.push(`./${srcDir}/${componentsDir}/${namespace}/app/app.ts`);
|
|
55
|
+
// Get local namespaces
|
|
56
|
+
const localNamespaces = await getDirectories(join(rootDir, srcDir, componentsDir));
|
|
57
|
+
// Get external namespaces; namespace, packageName
|
|
58
|
+
const externalNamespaces = new Map<string, string>();
|
|
59
|
+
for (let packageName of (external ?? [])) {
|
|
60
|
+
const folders = await getDirectories(join(rootDir, nodeModulesDir, ...packageName.split('/')));
|
|
61
|
+
folders.forEach((namespace) => {
|
|
62
|
+
if (namespace === nodeModulesDir) { return; }
|
|
63
|
+
externalNamespaces.set(namespace, packageName);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Autoload referenced html elements
|
|
67
|
+
plugins.push(htmlDependentsPlugin({
|
|
68
|
+
localNamespaces,
|
|
69
|
+
externalNamespaces,
|
|
70
|
+
}));
|
|
52
71
|
} else {
|
|
53
72
|
// dynamically resolve all found components
|
|
54
73
|
entryPoints.push('playground-entry');
|
package/scripts/element-start.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { context } from 'esbuild';
|
|
3
|
+
import { build, context } from 'esbuild';
|
|
4
4
|
import chokidar from 'chokidar';
|
|
5
5
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
6
6
|
import { join, sep, dirname } from 'node:path';
|
|
7
|
-
import { copyFile, readFile, writeFile } from 'node:fs/promises';
|
|
7
|
+
import { copyFile, cp, readFile, writeFile } from 'node:fs/promises';
|
|
8
8
|
|
|
9
9
|
import { fileExists } from '../scripts/fileExists.ts';
|
|
10
10
|
import { folderExists } from '../scripts/folderExists.ts';
|
|
@@ -12,10 +12,11 @@ import { playgroundPlugin } from '../scripts/playgroundPlugin.ts';
|
|
|
12
12
|
import { htmlDependentsPlugin } from '../scripts/htmlDependentsPlugin.ts';
|
|
13
13
|
import { rebuildNotifyPlugin } from '../scripts/rebuildNotifyPlugin.ts';
|
|
14
14
|
import { createPlaygroundIndex } from '../scripts/createPlaygroundIndex.ts';
|
|
15
|
+
import { getDirectories } from './getDirectories.ts';
|
|
15
16
|
|
|
16
17
|
(async () => {
|
|
17
18
|
|
|
18
|
-
const plugins = [
|
|
19
|
+
const plugins = [rebuildNotifyPlugin];
|
|
19
20
|
|
|
20
21
|
const bold = (text: string) => `\x1b[1m${text}\x1b[0m`;
|
|
21
22
|
const green = (text: string) => `\x1b[32m${text}\x1b[0m`;
|
|
@@ -39,11 +40,14 @@ const config = await import(fullConfigPath.href);
|
|
|
39
40
|
|
|
40
41
|
const {
|
|
41
42
|
namespace,
|
|
43
|
+
external,
|
|
42
44
|
title,
|
|
43
45
|
navigation,
|
|
44
46
|
repo,
|
|
45
47
|
repoComponent,
|
|
48
|
+
copy,
|
|
46
49
|
} = config.default;
|
|
50
|
+
const nodeModulesDir = 'node_modules';
|
|
47
51
|
const distDir = 'dist';
|
|
48
52
|
const srcDir = 'src';
|
|
49
53
|
const componentsDir = 'components';
|
|
@@ -52,6 +56,22 @@ const entryPoints: string[] = [];
|
|
|
52
56
|
if (namespace) {
|
|
53
57
|
console.log(green('Building app...'));
|
|
54
58
|
entryPoints.push(`./${srcDir}/${componentsDir}/${namespace}/app/app.ts`);
|
|
59
|
+
// Get local namespaces
|
|
60
|
+
const localNamespaces = await getDirectories(join(rootDir, srcDir, componentsDir));
|
|
61
|
+
// Get external namespaces; namespace, packageName
|
|
62
|
+
const externalNamespaces = new Map<string, string>();
|
|
63
|
+
for (let packageName of (external ?? [])) {
|
|
64
|
+
const folders = await getDirectories(join(rootDir, nodeModulesDir, ...packageName.split('/')));
|
|
65
|
+
folders.forEach((namespace) => {
|
|
66
|
+
if (namespace === nodeModulesDir) { return; }
|
|
67
|
+
externalNamespaces.set(namespace, packageName);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// Autoload referenced html elements
|
|
71
|
+
plugins.push(htmlDependentsPlugin({
|
|
72
|
+
localNamespaces,
|
|
73
|
+
externalNamespaces,
|
|
74
|
+
}));
|
|
55
75
|
// Handle index.html
|
|
56
76
|
const indexFile = 'index.html';
|
|
57
77
|
if (await fileExists(join(rootDir, srcDir, indexFile))) {
|
|
@@ -121,6 +141,7 @@ let ctx = await context({
|
|
|
121
141
|
bundle: true,
|
|
122
142
|
format: 'esm', // Use ES Modules
|
|
123
143
|
target: 'es2024', // Target ES6 syntax
|
|
144
|
+
sourcemap: true, // needed for debug
|
|
124
145
|
minify: false,
|
|
125
146
|
loader: {
|
|
126
147
|
'.css': 'text'
|
|
@@ -130,6 +151,24 @@ let ctx = await context({
|
|
|
130
151
|
|
|
131
152
|
// initial rebuild
|
|
132
153
|
await ctx.rebuild();
|
|
154
|
+
// copy folders and files
|
|
155
|
+
(copy ?? []).forEach(async ({ from, to }: { from: string, to: string }) => {
|
|
156
|
+
const toParts = to.split(sep);
|
|
157
|
+
const fromParts = from.split(sep);
|
|
158
|
+
if (fromParts[fromParts.length - 1] === '') {
|
|
159
|
+
console.log(red('element.config.ts "copy" "from" should not end with a "/". Ex: "assets" not "assets/".'));
|
|
160
|
+
process.exit();
|
|
161
|
+
}
|
|
162
|
+
if (toParts[toParts.length - 1] === '') {
|
|
163
|
+
console.log(red('element.config.ts "copy" "to" should not end with a "/". Ex: "assets" not "assets/".'));
|
|
164
|
+
process.exit();
|
|
165
|
+
}
|
|
166
|
+
if (await folderExists(join(rootDir, srcDir, ...fromParts))) {
|
|
167
|
+
await cp(join(rootDir, srcDir, ...fromParts), join(rootDir, distDir, ...toParts), { recursive: true });
|
|
168
|
+
} else if (await fileExists(join(rootDir, srcDir, ...fromParts))) {
|
|
169
|
+
await copyFile(join(rootDir, srcDir, ...fromParts), join(rootDir, distDir, ...toParts));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
133
172
|
|
|
134
173
|
// any change to src should trigger rebuild
|
|
135
174
|
const watcher = chokidar.watch('src', {
|
|
@@ -144,6 +183,23 @@ watcher.on('all', async (event, path) => {
|
|
|
144
183
|
console.log(`Copy "${parts.slice(2).join('/')}" to publish/*`);
|
|
145
184
|
await copyFile(join(rootDir, ...parts), join(rootDir, publishDir, ...parts.slice(2)));
|
|
146
185
|
}
|
|
186
|
+
// non destructive
|
|
187
|
+
if (event === 'change' || event === 'add') {
|
|
188
|
+
(copy ?? []).array.forEach(async ({ from, to }: { from: string, to: string }) => {
|
|
189
|
+
const withoutSrc = parts.slice(1).join('/');
|
|
190
|
+
if (withoutSrc.startsWith(from)) {
|
|
191
|
+
console.log('copy after', withoutSrc, from, to);
|
|
192
|
+
/*if (await folderExists(join(rootDir, ...parts))) {
|
|
193
|
+
await copyFile(join(rootDir, ...parts), join(rootDir, distDir, to, ...parts.slice(1)));
|
|
194
|
+
} else if (await fileExists(join(rootDir, ...parts))) {
|
|
195
|
+
await copyFile(join(rootDir, ...parts), join(rootDir, distDir, to, ...parts.slice(1)));
|
|
196
|
+
}*/
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
if (await folderExists(join(rootDir, ...parts))) {
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
}
|
|
147
203
|
}
|
|
148
204
|
try {
|
|
149
205
|
await ctx.rebuild();
|
|
@@ -3,43 +3,64 @@ import { readFile } from "node:fs/promises";
|
|
|
3
3
|
|
|
4
4
|
import { dashToCamel } from "./dashToCamel.ts";
|
|
5
5
|
|
|
6
|
+
const nodeModulesDir = 'node_modules';
|
|
6
7
|
const root = process.cwd();
|
|
7
8
|
const rootDepth = root.split(sep).length;
|
|
9
|
+
const red = (text: string) => `\x1b[31m${text}\x1b[0m`;
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
imports.push(`import './${backPaths.join('/')}/${component}/${component}';`);
|
|
34
|
-
} else {
|
|
35
|
-
imports.push(`import './${backPaths.join('/')}/${namespace}/${component}/${component}';`);
|
|
11
|
+
interface PluginOptions {
|
|
12
|
+
localNamespaces: string[];
|
|
13
|
+
externalNamespaces: Map<string, string>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function htmlDependentsPlugin({
|
|
17
|
+
localNamespaces,
|
|
18
|
+
externalNamespaces,
|
|
19
|
+
}: PluginOptions) {
|
|
20
|
+
return {
|
|
21
|
+
name: 'html-dependents-plugin',
|
|
22
|
+
setup(build: any) {
|
|
23
|
+
// Intercept files with the .html extension
|
|
24
|
+
build.onLoad({ filter: /\.html$/ }, async (args: any) => {
|
|
25
|
+
const parts = args.path.split(sep).splice(rootDepth);
|
|
26
|
+
const [src, componentsDir, currentNamspace, currentComponent, ...file] = parts;
|
|
27
|
+
// Read the file contents as text
|
|
28
|
+
const contents = await readFile(args.path, 'utf8');
|
|
29
|
+
const matches = contents.matchAll(/<\/(?<namespace>\w+)-(?<value>[^>]+)/g);
|
|
30
|
+
const components = new Map<string, string[]>();
|
|
31
|
+
for (const match of matches) {
|
|
32
|
+
const { namespace, value } = match.groups as any;
|
|
33
|
+
const component = dashToCamel(value);
|
|
34
|
+
components.set(`${namespace}-${component}`, [namespace, component]);
|
|
36
35
|
}
|
|
36
|
+
const imports: string[] = [];
|
|
37
|
+
components.forEach(([namespace, component]) => {
|
|
38
|
+
const depth = parts.length - 4;
|
|
39
|
+
const backPaths = (new Array(depth)).fill('..');
|
|
40
|
+
if (namespace === currentNamspace) {
|
|
41
|
+
if (component === currentComponent) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
imports.push(`import './${backPaths.join('/')}/${component}/${component}';`);
|
|
45
|
+
} else if (localNamespaces.includes(namespace)) {
|
|
46
|
+
imports.push(`import './${backPaths.join('/')}/${namespace}/${component}/${component}';`);
|
|
47
|
+
} else if (externalNamespaces.has(namespace)) {
|
|
48
|
+
backPaths.push('..'); // src
|
|
49
|
+
backPaths.push('..'); // components
|
|
50
|
+
backPaths.push('..'); // node_modules
|
|
51
|
+
const pkg = externalNamespaces.get(namespace);
|
|
52
|
+
imports.push(`import './${backPaths.join('/')}/${nodeModulesDir}/${pkg}/${namespace}/${component}/${component}';`);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(red(`Unable to find namespace folder "${namespace}". Possibly missing 'external' in element.config.ts`));
|
|
55
|
+
process.exit();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
imports.push(`export default \`${contents}\`;`);
|
|
59
|
+
return {
|
|
60
|
+
contents: imports.join('\n'),
|
|
61
|
+
loader: 'js',
|
|
62
|
+
};
|
|
37
63
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
loader: 'js',
|
|
42
|
-
};
|
|
43
|
-
});
|
|
44
|
-
},
|
|
45
|
-
};
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|