@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pictogrammers/element-esbuild",
3
- "version": "0.0.13",
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",
@@ -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 = [htmlDependentsPlugin, rebuildNotifyPlugin];
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');
@@ -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 = [htmlDependentsPlugin, rebuildNotifyPlugin];
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();
@@ -1,5 +1,4 @@
1
1
  import {readdir} from 'node:fs/promises';
2
- import { join } from 'node:path';
3
2
 
4
3
  export async function getDirectories(dirPath: string) {
5
4
  const directories: string[] = [];
@@ -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
- export const htmlDependentsPlugin = {
10
- name: 'html-dependents-plugin',
11
- setup(build: any) {
12
- // Intercept files with the .html extension
13
- build.onLoad({ filter: /\.html$/ }, async (args: any) => {
14
- const parts = args.path.split(sep).splice(rootDepth);
15
- const [src, componentsDir, currentNamspace, currentComponent, ...file] = parts;
16
- // Read the file contents as text
17
- const contents = await readFile(args.path, 'utf8');
18
- const matches = contents.matchAll(/<\/(?<namespace>\w+)-(?<value>[^>]+)/g);
19
- const components = new Map<string, string[]>();
20
- for (const match of matches) {
21
- const { namespace, value } = match.groups as any;
22
- const component = dashToCamel(value);
23
- components.set(`${namespace}-${component}`, [namespace, component]);
24
- }
25
- const imports: string[] = [];
26
- components.forEach(([namespace, component]) => {
27
- const depth = parts.length - 4;
28
- const backPaths = (new Array(depth)).fill('..');
29
- if (namespace === currentNamspace) {
30
- if (component === currentComponent) {
31
- return;
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
- imports.push(`export default \`${contents}\`;`);
39
- return {
40
- contents: imports.join('\n'),
41
- loader: 'js',
42
- };
43
- });
44
- },
45
- };
64
+ },
65
+ };
66
+ }