@package-verse/esmpack 1.0.9 → 1.0.11
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 +2 -1
- package/src/pack/FilePacker.ts +50 -4
- package/src/parser/babel.ts +74 -14
- package/src/serve/send/packageInfo.ts +18 -3
- package/src/serve/send/sendJS.ts +20 -82
- package/src/serve/send/sendLocalFile.ts +2 -1
- package/src/test/TestView.local.css +12 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@package-verse/esmpack",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "ESM Pack Packer and Web Server with PostCSS and ESM Loader",
|
|
5
5
|
"homepage": "https://github.com/package-verse/esmpack#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"postversion": "git push --follow-tags"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@types/babel__core": "^7.20.5",
|
|
24
25
|
"@types/node": "^25.5.0",
|
|
25
26
|
"@types/ws": "^8.18.1",
|
|
26
27
|
"cssnano": "^7.0.6",
|
package/src/pack/FilePacker.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { Babel } from "../parser/babel.js";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* File Packer must do following tasks...
|
|
3
6
|
* 1. Visit every JavaScript file
|
|
@@ -10,11 +13,12 @@
|
|
|
10
13
|
* Push Import Maps script tag
|
|
11
14
|
* Add import map for non js modules as well, and for this
|
|
12
15
|
* every nested dependency must be inspected.
|
|
16
|
+
* Json module should load json via hashed-dependency
|
|
17
|
+
* Image module should load path of module via hashed-dependency
|
|
18
|
+
* CSS module should inject full path to the browser
|
|
13
19
|
* Push empty module for CSS
|
|
14
20
|
* Imports all nested dependencies of App.js that should not contain fully qualified path
|
|
15
21
|
* Import dynamically loaded modules as well
|
|
16
|
-
* Loads App.pack.global.css
|
|
17
|
-
* Loads App.pack.local.css
|
|
18
22
|
* Imports App.js dynamically so CSS can be ready before hosting the User interface
|
|
19
23
|
* 2. App.pack.global.css
|
|
20
24
|
* 3. App.pack.local.css
|
|
@@ -23,8 +27,13 @@
|
|
|
23
27
|
*/
|
|
24
28
|
export default class FilePacker {
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
readonly absoluteSrc: string;
|
|
31
|
+
|
|
32
|
+
readonly cssImports = [];
|
|
33
|
+
|
|
34
|
+
readonly jsonImports = [];
|
|
35
|
+
|
|
36
|
+
readonly pathImports = [];
|
|
28
37
|
|
|
29
38
|
constructor(
|
|
30
39
|
public readonly root: string,
|
|
@@ -32,10 +41,47 @@ export default class FilePacker {
|
|
|
32
41
|
public readonly prefix: string
|
|
33
42
|
) {
|
|
34
43
|
// empty
|
|
44
|
+
// let us make src relative to the root if an absolute path was supplied
|
|
45
|
+
if (path.isAbsolute(this.src)) {
|
|
46
|
+
this.src = path.relative(this.root, this.src);
|
|
47
|
+
}
|
|
48
|
+
this.absoluteSrc = path.resolve(this.root, this.src);
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
async pack() {
|
|
38
52
|
|
|
53
|
+
const resolve = (url, sourceFile) => this.resolve(url, sourceFile);
|
|
54
|
+
|
|
55
|
+
// we don't need the code
|
|
56
|
+
await Babel.transformAsync({
|
|
57
|
+
file: path.join(this.root, this.src),
|
|
58
|
+
resolve,
|
|
59
|
+
dynamicResolve: resolve
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
|
|
39
63
|
}
|
|
40
64
|
|
|
65
|
+
resolve(url: string, sourceFile: string) {
|
|
66
|
+
|
|
67
|
+
const moduleUrl = this.moduleUrl(url, sourceFile);
|
|
68
|
+
|
|
69
|
+
if (url.endsWith(".css")) {
|
|
70
|
+
this.cssImports.push(moduleUrl);
|
|
71
|
+
return url;
|
|
72
|
+
}
|
|
73
|
+
if (url.endsWith(".json")) {
|
|
74
|
+
this.jsonImports.push(moduleUrl);
|
|
75
|
+
return url;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!url.endsWith(".js")) {
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
return url;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
moduleUrl(url: string, sourceFile: string) {
|
|
85
|
+
return url;
|
|
86
|
+
}
|
|
41
87
|
}
|
package/src/parser/babel.ts
CHANGED
|
@@ -1,18 +1,83 @@
|
|
|
1
|
-
import { transformSync } from "@babel/core";
|
|
1
|
+
import { NodePath, TransformOptions, transformSync } from "@babel/core";
|
|
2
2
|
import { readFileSync } from "fs";
|
|
3
3
|
import { ProcessOptions } from "../ProcessArgs.js";
|
|
4
4
|
import { parse } from "path";
|
|
5
|
+
import { CallExpression, ImportDeclaration, ImportExpression } from "@babel/types";
|
|
6
|
+
import { readFile } from "fs/promises";
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
export class Babel {
|
|
7
10
|
|
|
8
|
-
static transform({
|
|
11
|
+
static transform({
|
|
12
|
+
file,
|
|
13
|
+
resolve,
|
|
14
|
+
dynamicResolve
|
|
15
|
+
}: {
|
|
16
|
+
file: string,
|
|
17
|
+
resolve: (url: string, sourceFile: string) => string,
|
|
18
|
+
dynamicResolve?: (url: string, sourceFile: string) => string
|
|
19
|
+
}) {
|
|
20
|
+
|
|
21
|
+
const presets: TransformOptions = Babel.prepareOptions(file, dynamicResolve, resolve);
|
|
22
|
+
|
|
23
|
+
const p = { ... presets, filename: file };
|
|
24
|
+
const code = readFileSync(file, "utf8");
|
|
25
|
+
const result = transformSync(code, p);
|
|
26
|
+
return result.code;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static async transformAsync({
|
|
30
|
+
file,
|
|
31
|
+
resolve,
|
|
32
|
+
dynamicResolve
|
|
33
|
+
}) {
|
|
34
|
+
const presets: TransformOptions = Babel.prepareOptions(file, dynamicResolve, resolve);
|
|
35
|
+
|
|
36
|
+
const p = { ... presets, filename: file };
|
|
37
|
+
const code = await readFile(file, "utf8");
|
|
38
|
+
const result = transformSync(code, p);
|
|
39
|
+
return result.code;
|
|
9
40
|
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private static prepareOptions(file: string, dynamicResolve: (url: string, sourceFile: string) => string, resolve: (url: string, sourceFile: string) => string) {
|
|
10
44
|
const { base: name } = parse(file);
|
|
11
45
|
|
|
12
|
-
|
|
46
|
+
function CallExpression(node: NodePath<CallExpression>) {
|
|
47
|
+
if (node.node.callee.type !== "Import") {
|
|
48
|
+
return node;
|
|
49
|
+
}
|
|
50
|
+
const sourceFile = (node.hub as any)?.file?.inputMap?.sourcemap?.sources?.[0];
|
|
51
|
+
const [arg1] = node.node.arguments;
|
|
52
|
+
if (!arg1) {
|
|
53
|
+
return node;
|
|
54
|
+
}
|
|
55
|
+
if (arg1.type !== "StringLiteral") {
|
|
56
|
+
return node;
|
|
57
|
+
}
|
|
58
|
+
const v = dynamicResolve(arg1.value, sourceFile);
|
|
59
|
+
if (v !== arg1.value) {
|
|
60
|
+
arg1.value = v || arg1.value;
|
|
61
|
+
}
|
|
62
|
+
return node;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function ImportExpression(node: NodePath<ImportExpression>) {
|
|
66
|
+
const sourceFile = (node.hub as any)?.file?.inputMap?.sourcemap?.sources?.[0];
|
|
67
|
+
const { source } = node.node;
|
|
68
|
+
if (source.type !== "StringLiteral") {
|
|
69
|
+
return node;
|
|
70
|
+
}
|
|
71
|
+
const v = dynamicResolve(source.value, sourceFile);
|
|
72
|
+
if (v !== source.value) {
|
|
73
|
+
source.value = v || source.value;
|
|
74
|
+
}
|
|
75
|
+
return node;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const presets: TransformOptions = {
|
|
13
79
|
sourceType: "module",
|
|
14
80
|
sourceMaps: true,
|
|
15
|
-
inputSourceMap: true,
|
|
16
81
|
caller: {
|
|
17
82
|
name,
|
|
18
83
|
supportsDynamicImport: true,
|
|
@@ -24,33 +89,28 @@ export class Babel {
|
|
|
24
89
|
getModuleId: () => "v",
|
|
25
90
|
"plugins": [
|
|
26
91
|
[
|
|
27
|
-
function(babel) {
|
|
92
|
+
function (babel) {
|
|
28
93
|
return {
|
|
29
94
|
name: "Import Transformer",
|
|
30
95
|
visitor: {
|
|
31
|
-
ImportDeclaration(node) {
|
|
96
|
+
ImportDeclaration(node: NodePath<ImportDeclaration>) {
|
|
32
97
|
const e = node.node;
|
|
33
98
|
let source = e.source?.value;
|
|
34
99
|
if (!source) {
|
|
35
100
|
return node;
|
|
36
101
|
}
|
|
37
|
-
const sourceFile = node.hub?.file?.inputMap?.sourcemap?.sources?.[0];
|
|
102
|
+
const sourceFile = (node.hub as any)?.file?.inputMap?.sourcemap?.sources?.[0];
|
|
38
103
|
source = resolve(source, sourceFile);
|
|
39
104
|
e.source.value = source;
|
|
40
105
|
return node;
|
|
41
106
|
},
|
|
107
|
+
...(dynamicResolve ? { CallExpression, ImportExpression } : {}),
|
|
42
108
|
}
|
|
43
109
|
};
|
|
44
110
|
}
|
|
45
111
|
]
|
|
46
|
-
|
|
47
112
|
]
|
|
48
113
|
};
|
|
49
|
-
|
|
50
|
-
const p = { ... presets, filename: file };
|
|
51
|
-
const code = readFileSync(file, "utf8");
|
|
52
|
-
const result = transformSync(code, p);
|
|
53
|
-
return result.code;
|
|
114
|
+
return presets;
|
|
54
115
|
}
|
|
55
|
-
|
|
56
116
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
import { ProcessOptions } from "../../ProcessArgs.js";
|
|
3
|
-
import { join } from "path";
|
|
3
|
+
import path, { join } from "path/posix";
|
|
4
4
|
|
|
5
5
|
const jsonText = readFileSync(join(ProcessOptions.cwd, "package.json"), "utf-8");
|
|
6
6
|
|
|
@@ -11,7 +11,22 @@ const imports = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
for (const [key] of Object.entries(packageInfo.dependencies)) {
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
const modulePackageJsonFilePath = join(ProcessOptions.cwd, "node_modules", key , "package.json");
|
|
16
|
+
if (!existsSync(modulePackageJsonFilePath)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const modulePath = "/node_modules/" + key + "/";
|
|
21
|
+
|
|
22
|
+
// read package.json
|
|
23
|
+
const modulePackageJson = JSON.parse(readFileSync(modulePackageJsonFilePath, "utf-8"));
|
|
24
|
+
imports[key] = path.join(modulePath , modulePackageJson.module
|
|
25
|
+
|| (modulePackageJson.type === "module"
|
|
26
|
+
? modulePackageJson.main : "index.js"));
|
|
27
|
+
|
|
28
|
+
imports[key + "/"] = modulePath;
|
|
29
|
+
|
|
15
30
|
}
|
|
16
31
|
|
|
17
32
|
export const importMap = { imports };
|
package/src/serve/send/sendJS.ts
CHANGED
|
@@ -1,64 +1,42 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { Babel } from "../../parser/babel.js";
|
|
3
3
|
import path, { parse } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
6
5
|
|
|
7
6
|
export default function sendJS(filePath: string, req: IncomingMessage, res: ServerResponse) {
|
|
8
7
|
|
|
8
|
+
const resolve = (url: string, sourceFile: string) => {
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
if (url.endsWith(".js")) {
|
|
11
|
+
return url;
|
|
12
|
+
}
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
if(!sourceFile) {
|
|
15
|
+
sourceFile = filePath;
|
|
16
|
+
}
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
const { ext } = parse(url);
|
|
16
|
-
if (!ext) {
|
|
18
|
+
if (!url.startsWith(".")) {
|
|
17
19
|
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
// fetch module...
|
|
20
|
+
// we need to include .js for every module relative path
|
|
21
21
|
const tokens = url.split("/");
|
|
22
22
|
let packageName = tokens.shift();
|
|
23
23
|
if (packageName.startsWith("@")) {
|
|
24
24
|
packageName += "/" + tokens.shift();
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return url + "/" + start;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!url.startsWith(".")) {
|
|
38
|
-
|
|
39
|
-
if (!url.endsWith(".js")) {
|
|
40
|
-
url += ".js";
|
|
27
|
+
if (tokens.length) {
|
|
28
|
+
if (!url.endsWith(".js")) {
|
|
29
|
+
return url + ".js";
|
|
30
|
+
}
|
|
41
31
|
}
|
|
42
32
|
|
|
43
33
|
return url;
|
|
44
34
|
}
|
|
45
35
|
|
|
46
|
-
const jsFile = path.resolve(path.dirname(filePath), url);
|
|
47
|
-
if (existsSync(jsFile)) {
|
|
48
|
-
if (!jsFile.endsWith(".js")) {
|
|
49
|
-
url += ".js";
|
|
50
|
-
}
|
|
51
|
-
return url;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (url.endsWith(".js")) {
|
|
55
|
-
return url;
|
|
56
|
-
}
|
|
57
36
|
|
|
58
37
|
// is it referenced from source...
|
|
59
38
|
const dir = path.dirname(filePath);
|
|
60
39
|
const absoluteSourcePath = path.resolve( dir, path.dirname(sourceFile));
|
|
61
|
-
console.log(`Absolute Path is ${absoluteSourcePath}`);
|
|
62
40
|
const referencedAbsolutePath = path.join(absoluteSourcePath, url);
|
|
63
41
|
if (existsSync(referencedAbsolutePath)) {
|
|
64
42
|
const relative = path.relative(dir, referencedAbsolutePath).replaceAll("\\", "/");
|
|
@@ -67,58 +45,18 @@ export default function sendJS(filePath: string, req: IncomingMessage, res: Serv
|
|
|
67
45
|
}
|
|
68
46
|
return relative;
|
|
69
47
|
}
|
|
70
|
-
return originalUrl;
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
|
|
50
|
+
return url + ".js";
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
let text = Babel.transform({ file: filePath, resolve, dynamicResolve: resolve});
|
|
73
55
|
|
|
74
56
|
const { base } = parse(filePath);
|
|
75
57
|
|
|
76
58
|
text += `\n//# sourceMappingURL=${base}.map`;
|
|
77
59
|
|
|
78
|
-
// let text = readFileSync(path, "utf-8");
|
|
79
|
-
|
|
80
|
-
// // change references....
|
|
81
|
-
// // text = text.replace(/from\s*\"([^\.][^\"]+)\"/gm, `from "/node_modules/$1"`);
|
|
82
|
-
|
|
83
|
-
// // remap CSS
|
|
84
|
-
// text = RegExpExtra.replaceAll(text, /from\s*\"([^\"]+)\"/gm, (
|
|
85
|
-
// { text, match }
|
|
86
|
-
// ) => {
|
|
87
|
-
// if (text) {
|
|
88
|
-
// return text;
|
|
89
|
-
// }
|
|
90
|
-
// const [matched, g] = match;
|
|
91
|
-
// if (g.endsWith(".css")) {
|
|
92
|
-
// // we need to find source...
|
|
93
|
-
// return `from "/node_modules/${g}.js"`;
|
|
94
|
-
// }
|
|
95
|
-
// if (g.startsWith(".")) {
|
|
96
|
-
// return matched;
|
|
97
|
-
// }
|
|
98
|
-
// return `from "/node_modules/${g}"`;
|
|
99
|
-
// });
|
|
100
|
-
|
|
101
|
-
// text = RegExpExtra.replaceAll(text, /import\s*\"([^\"]+)\"/gm, (
|
|
102
|
-
// { text, match }
|
|
103
|
-
// ) => {
|
|
104
|
-
// if (text) {
|
|
105
|
-
// return text;
|
|
106
|
-
// }
|
|
107
|
-
// const [matched, g] = match;
|
|
108
|
-
// if (g.endsWith(".css")) {
|
|
109
|
-
// // we need to find source...
|
|
110
|
-
// let cssPath = g;
|
|
111
|
-
// if (!cssPath.startsWith(".")) {
|
|
112
|
-
// cssPath = "/node_modules/" + cssPath;
|
|
113
|
-
// }
|
|
114
|
-
// return `import "${cssPath}.js"`;
|
|
115
|
-
// }
|
|
116
|
-
// if (g.startsWith(".")) {
|
|
117
|
-
// return matched;
|
|
118
|
-
// }
|
|
119
|
-
// return `import "/node_modules/${g}"`;
|
|
120
|
-
// });
|
|
121
|
-
|
|
122
60
|
res.writeHead(200, {
|
|
123
61
|
"content-type": "text/javascript",
|
|
124
62
|
"cache-control": "no-cache"
|
|
@@ -5,7 +5,8 @@ import sendList from "./sendList.js";
|
|
|
5
5
|
import sendJS from "./sendJS.js";
|
|
6
6
|
export default function sendLocalFile(reqPath: string, path: string, req: IncomingMessage, res: ServerResponse) {
|
|
7
7
|
|
|
8
|
-
if (path.endsWith(".js")
|
|
8
|
+
if (path.endsWith(".js")
|
|
9
|
+
&& !path.endsWith(".pack.js")) {
|
|
9
10
|
// send JS
|
|
10
11
|
return sendJS(path, req, res);
|
|
11
12
|
}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
1
|
date-view {
|
|
2
2
|
color: red;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: row;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-items: center;
|
|
7
|
+
align-content: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
gap: 10px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
date-view img {
|
|
13
|
+
max-height: 50px;
|
|
14
|
+
max-width: 50px;
|
|
3
15
|
}
|