@jsenv/core 29.6.1 → 29.7.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/{readme.md → README.md} +2 -28
- package/dist/main.js +145 -89
- package/package.json +4 -4
- package/src/dev/start_dev_server.js +8 -0
- package/src/main.js +2 -2
- package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +20 -8
- package/src/plugins/minification/jsenv_plugin_minification.js +27 -24
- package/src/plugins/placeholders/jsenv_plugin_placeholders.js +36 -0
- package/src/{helpers → plugins/placeholders}/replace_placeholders.js +10 -2
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +1 -1
- package/src/plugins/url_version/jsenv_plugin_url_version.js +1 -1
package/{readme.md → README.md}
RENAMED
|
@@ -7,26 +7,9 @@ It has naturally evolved to cover the core needs of a JavaScript project: develo
|
|
|
7
7
|
- :sparkles: Dev, tests and build in a single tool
|
|
8
8
|
- :ok_hand: Seamless integration with standard HTML, CSS and JS
|
|
9
9
|
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
The following command can be used to create a jsenv project on a machine.
|
|
13
|
-
|
|
14
|
-
```console
|
|
15
|
-
npm create jsenv@latest
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
This command prompts to choose a demo from a list.
|
|
19
|
-
Each demo contains preconfigured scripts:
|
|
20
|
-
|
|
21
|
-
- `npm run dev`: starts a dev server with autoreload.
|
|
22
|
-
- `npm run test`: execute test files on browsers(s) and/or Node.js.
|
|
23
|
-
- `npm run build`: generate files optimized for production.
|
|
24
|
-
|
|
25
|
-
> **Info**
|
|
26
|
-
> Executing "npm install" in web demos can take time.
|
|
27
|
-
> It is because in these demos tests are runned in headless browsers that needs to be installed first.
|
|
10
|
+
# Documentation
|
|
28
11
|
|
|
29
|
-
|
|
12
|
+
https://github.com/jsenv/jsenv-core/wiki
|
|
30
13
|
|
|
31
14
|
# Installation
|
|
32
15
|
|
|
@@ -36,15 +19,6 @@ npm install --save-dev @jsenv/core
|
|
|
36
19
|
|
|
37
20
|
_@jsenv/core_ is tested on Mac, Windows, Linux with Node.js 18.5.0. Other operating systems and Node.js versions are not tested.
|
|
38
21
|
|
|
39
|
-
# Documentation
|
|
40
|
-
|
|
41
|
-
| Link | Description |
|
|
42
|
-
| -------------------------------------------------- | ---------------------------------------------- |
|
|
43
|
-
| [Browser support](./docs/browser_support.md) | Documentation around browser support |
|
|
44
|
-
| [Assets and workers](./docs/assets_and_workers.md) | How to reference files within a file |
|
|
45
|
-
| [Import resolution](./docs/import_resolution.md) | Import resolution inside js modules |
|
|
46
|
-
| [NPM package](./docs/npm_package.md) | How to use a NPM package (especially commonjs) |
|
|
47
|
-
|
|
48
22
|
# Name
|
|
49
23
|
|
|
50
24
|
The name "jsenv" stands for JavaScript environments. This is because the original purpose of jsenv was to bring closer two JavaScript runtimes: web browsers and Node.js.
|
package/dist/main.js
CHANGED
|
@@ -337,9 +337,12 @@ const pathnameToExtension$1 = pathname => {
|
|
|
337
337
|
};
|
|
338
338
|
|
|
339
339
|
const asUrlWithoutSearch = url => {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
if (url.includes("?")) {
|
|
341
|
+
const urlObject = new URL(url);
|
|
342
|
+
urlObject.search = "";
|
|
343
|
+
return urlObject.href;
|
|
344
|
+
}
|
|
345
|
+
return url;
|
|
343
346
|
};
|
|
344
347
|
|
|
345
348
|
// normalize url search params:
|
|
@@ -19273,7 +19276,7 @@ const jsenvPluginUrlResolution = ({
|
|
|
19273
19276
|
const jsenvPluginUrlVersion = () => {
|
|
19274
19277
|
return {
|
|
19275
19278
|
name: "jsenv:url_version",
|
|
19276
|
-
appliesDuring: "
|
|
19279
|
+
appliesDuring: "dev",
|
|
19277
19280
|
redirectUrl: reference => {
|
|
19278
19281
|
// "v" search param goal is to enable long-term cache
|
|
19279
19282
|
// for server response headers
|
|
@@ -21708,27 +21711,30 @@ const jsenvPluginMinification = minification => {
|
|
|
21708
21711
|
context,
|
|
21709
21712
|
options: minification.json
|
|
21710
21713
|
}) : null;
|
|
21714
|
+
const cssOptimizer = minification.css ? (urlInfo, context) => minifyCss({
|
|
21715
|
+
cssUrlInfo: urlInfo,
|
|
21716
|
+
context,
|
|
21717
|
+
options: minification.css
|
|
21718
|
+
}) : null;
|
|
21719
|
+
const jsClassicOptimizer = minification.js_classic ? (urlInfo, context) => minifyJs({
|
|
21720
|
+
jsUrlInfo: urlInfo,
|
|
21721
|
+
context,
|
|
21722
|
+
options: minification.js_classic
|
|
21723
|
+
}) : null;
|
|
21724
|
+
const jsModuleOptimizer = minification.js_module ? (urlInfo, context) => minifyJs({
|
|
21725
|
+
jsUrlInfo: urlInfo,
|
|
21726
|
+
context,
|
|
21727
|
+
options: minification.js_module
|
|
21728
|
+
}) : null;
|
|
21711
21729
|
return {
|
|
21712
21730
|
name: "jsenv:minification",
|
|
21713
21731
|
appliesDuring: "build",
|
|
21714
21732
|
optimizeUrlContent: {
|
|
21715
21733
|
html: htmlOptimizer,
|
|
21716
21734
|
svg: htmlOptimizer,
|
|
21717
|
-
css:
|
|
21718
|
-
|
|
21719
|
-
|
|
21720
|
-
options: minification.css
|
|
21721
|
-
}) : null,
|
|
21722
|
-
js_classic: minification.js_classic ? (urlInfo, context) => minifyJs({
|
|
21723
|
-
jsUrlInfo: urlInfo,
|
|
21724
|
-
context,
|
|
21725
|
-
options: minification.js_classic
|
|
21726
|
-
}) : null,
|
|
21727
|
-
js_module: minification.js_module ? (urlInfo, context) => minifyJs({
|
|
21728
|
-
jsUrlInfo: urlInfo,
|
|
21729
|
-
context,
|
|
21730
|
-
options: minification.js_module
|
|
21731
|
-
}) : null,
|
|
21735
|
+
css: cssOptimizer,
|
|
21736
|
+
js_classic: jsClassicOptimizer,
|
|
21737
|
+
js_module: jsModuleOptimizer,
|
|
21732
21738
|
json: jsonOptimizer,
|
|
21733
21739
|
importmap: jsonOptimizer,
|
|
21734
21740
|
webmanifest: jsonOptimizer
|
|
@@ -22460,7 +22466,7 @@ const jsenvPluginExplorer = ({
|
|
|
22460
22466
|
|
|
22461
22467
|
const jsenvPluginRibbon = ({
|
|
22462
22468
|
rootDirectoryUrl,
|
|
22463
|
-
htmlInclude = "
|
|
22469
|
+
htmlInclude = "/**/*.html"
|
|
22464
22470
|
}) => {
|
|
22465
22471
|
const ribbonClientFileUrl = new URL("./js/ribbon.js", import.meta.url);
|
|
22466
22472
|
const associations = URL_META.resolveAssociations({
|
|
@@ -24801,6 +24807,14 @@ const inferParentFromRequest = (request, rootDirectoryUrl) => {
|
|
|
24801
24807
|
});
|
|
24802
24808
|
};
|
|
24803
24809
|
|
|
24810
|
+
/**
|
|
24811
|
+
* Start a server for source files:
|
|
24812
|
+
* - cook source files according to jsenv plugins
|
|
24813
|
+
* - inject code to autoreload the browser when a file is modified
|
|
24814
|
+
* @param {Object} devServerParameters
|
|
24815
|
+
* @param {string|url} devServerParameters.rootDirectoryUrl Root directory of the project
|
|
24816
|
+
* @return {Object} A dev server object
|
|
24817
|
+
*/
|
|
24804
24818
|
const startDevServer = async ({
|
|
24805
24819
|
signal = new AbortController().signal,
|
|
24806
24820
|
handleSIGINT = true,
|
|
@@ -28394,7 +28408,83 @@ const createBuildFilesService = ({
|
|
|
28394
28408
|
};
|
|
28395
28409
|
const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
|
|
28396
28410
|
|
|
28397
|
-
const
|
|
28411
|
+
const injectGlobals = (urlInfo, globals) => {
|
|
28412
|
+
if (urlInfo.type === "html") {
|
|
28413
|
+
return globalInjectorOnHtml(urlInfo, globals);
|
|
28414
|
+
}
|
|
28415
|
+
if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
|
|
28416
|
+
return globalsInjectorOnJs(urlInfo, globals);
|
|
28417
|
+
}
|
|
28418
|
+
throw new Error(`cannot inject globals into "${urlInfo.type}"`);
|
|
28419
|
+
};
|
|
28420
|
+
const globalInjectorOnHtml = async (urlInfo, globals) => {
|
|
28421
|
+
// ideally we would inject an importmap but browser support is too low
|
|
28422
|
+
// (even worse for worker/service worker)
|
|
28423
|
+
// so for now we inject code into entry points
|
|
28424
|
+
const htmlAst = parseHtmlString(urlInfo.content, {
|
|
28425
|
+
storeOriginalPositions: false
|
|
28426
|
+
});
|
|
28427
|
+
const clientCode = generateClientCodeForGlobals({
|
|
28428
|
+
globals,
|
|
28429
|
+
isWebWorker: false
|
|
28430
|
+
});
|
|
28431
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
28432
|
+
tagName: "script",
|
|
28433
|
+
textContent: clientCode
|
|
28434
|
+
}), "jsenv:inject_globals");
|
|
28435
|
+
return stringifyHtmlAst(htmlAst);
|
|
28436
|
+
};
|
|
28437
|
+
const globalsInjectorOnJs = async (urlInfo, globals) => {
|
|
28438
|
+
const clientCode = generateClientCodeForGlobals({
|
|
28439
|
+
globals,
|
|
28440
|
+
isWebWorker: urlInfo.subtype === "worker" || urlInfo.subtype === "service_worker" || urlInfo.subtype === "shared_worker"
|
|
28441
|
+
});
|
|
28442
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
28443
|
+
magicSource.prepend(clientCode);
|
|
28444
|
+
return magicSource.toContentAndSourcemap();
|
|
28445
|
+
};
|
|
28446
|
+
const generateClientCodeForGlobals = ({
|
|
28447
|
+
isWebWorker = false,
|
|
28448
|
+
globals
|
|
28449
|
+
}) => {
|
|
28450
|
+
const globalName = isWebWorker ? "self" : "window";
|
|
28451
|
+
return `Object.assign(${globalName}, ${JSON.stringify(globals, null, " ")});`;
|
|
28452
|
+
};
|
|
28453
|
+
|
|
28454
|
+
const jsenvPluginInjectGlobals = rawAssociations => {
|
|
28455
|
+
let resolvedAssociations;
|
|
28456
|
+
return {
|
|
28457
|
+
name: "jsenv:inject_globals",
|
|
28458
|
+
appliesDuring: "*",
|
|
28459
|
+
init: context => {
|
|
28460
|
+
resolvedAssociations = URL_META.resolveAssociations({
|
|
28461
|
+
injector: rawAssociations
|
|
28462
|
+
}, context.rootDirectoryUrl);
|
|
28463
|
+
},
|
|
28464
|
+
transformUrlContent: async (urlInfo, context) => {
|
|
28465
|
+
const {
|
|
28466
|
+
injector
|
|
28467
|
+
} = URL_META.applyAssociations({
|
|
28468
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
28469
|
+
associations: resolvedAssociations
|
|
28470
|
+
});
|
|
28471
|
+
if (!injector) {
|
|
28472
|
+
return null;
|
|
28473
|
+
}
|
|
28474
|
+
if (typeof injector !== "function") {
|
|
28475
|
+
throw new TypeError("injector must be a function");
|
|
28476
|
+
}
|
|
28477
|
+
const globals = await injector(urlInfo, context);
|
|
28478
|
+
if (!globals || Object.keys(globals).length === 0) {
|
|
28479
|
+
return null;
|
|
28480
|
+
}
|
|
28481
|
+
return injectGlobals(urlInfo, globals);
|
|
28482
|
+
}
|
|
28483
|
+
};
|
|
28484
|
+
};
|
|
28485
|
+
|
|
28486
|
+
const replacePlaceholders = (urlInfo, replacements) => {
|
|
28487
|
+
const content = urlInfo.content;
|
|
28398
28488
|
const magicSource = createMagicSource(content);
|
|
28399
28489
|
Object.keys(replacements).forEach(key => {
|
|
28400
28490
|
let index = content.indexOf(key);
|
|
@@ -28404,7 +28494,7 @@ const replacePlaceholders = (content, replacements) => {
|
|
|
28404
28494
|
magicSource.replace({
|
|
28405
28495
|
start,
|
|
28406
28496
|
end,
|
|
28407
|
-
replacement: replacements[key]
|
|
28497
|
+
replacement: urlInfo.type === "js_classic" || urlInfo.type === "js_module" ? JSON.stringify(replacements[key], null, " ") : replacements[key]
|
|
28408
28498
|
});
|
|
28409
28499
|
index = content.indexOf(key, end);
|
|
28410
28500
|
}
|
|
@@ -28412,6 +28502,38 @@ const replacePlaceholders = (content, replacements) => {
|
|
|
28412
28502
|
return magicSource.toContentAndSourcemap();
|
|
28413
28503
|
};
|
|
28414
28504
|
|
|
28505
|
+
const jsenvPluginPlaceholders = rawAssociations => {
|
|
28506
|
+
let resolvedAssociations;
|
|
28507
|
+
return {
|
|
28508
|
+
name: "jsenv:placeholders",
|
|
28509
|
+
appliesDuring: "*",
|
|
28510
|
+
init: context => {
|
|
28511
|
+
resolvedAssociations = URL_META.resolveAssociations({
|
|
28512
|
+
replacer: rawAssociations
|
|
28513
|
+
}, context.rootDirectoryUrl);
|
|
28514
|
+
},
|
|
28515
|
+
transformUrlContent: async (urlInfo, context) => {
|
|
28516
|
+
const {
|
|
28517
|
+
replacer
|
|
28518
|
+
} = URL_META.applyAssociations({
|
|
28519
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
28520
|
+
associations: resolvedAssociations
|
|
28521
|
+
});
|
|
28522
|
+
if (!replacer) {
|
|
28523
|
+
return null;
|
|
28524
|
+
}
|
|
28525
|
+
if (typeof replacer !== "function") {
|
|
28526
|
+
throw new TypeError("replacer must be a function");
|
|
28527
|
+
}
|
|
28528
|
+
const replacements = await replacer(urlInfo, context);
|
|
28529
|
+
if (!replacements || Object.keys(replacements).length === 0) {
|
|
28530
|
+
return null;
|
|
28531
|
+
}
|
|
28532
|
+
return replacePlaceholders(urlInfo, replacements);
|
|
28533
|
+
}
|
|
28534
|
+
};
|
|
28535
|
+
};
|
|
28536
|
+
|
|
28415
28537
|
const execute = async ({
|
|
28416
28538
|
signal = new AbortController().signal,
|
|
28417
28539
|
handleSIGINT = true,
|
|
@@ -28497,70 +28619,4 @@ const execute = async ({
|
|
|
28497
28619
|
}
|
|
28498
28620
|
};
|
|
28499
28621
|
|
|
28500
|
-
|
|
28501
|
-
if (urlInfo.type === "html") {
|
|
28502
|
-
return globalInjectorOnHtml(urlInfo, globals);
|
|
28503
|
-
}
|
|
28504
|
-
if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
|
|
28505
|
-
return globalsInjectorOnJs(urlInfo, globals);
|
|
28506
|
-
}
|
|
28507
|
-
throw new Error(`cannot inject globals into "${urlInfo.type}"`);
|
|
28508
|
-
};
|
|
28509
|
-
const globalInjectorOnHtml = async (urlInfo, globals) => {
|
|
28510
|
-
// ideally we would inject an importmap but browser support is too low
|
|
28511
|
-
// (even worse for worker/service worker)
|
|
28512
|
-
// so for now we inject code into entry points
|
|
28513
|
-
const htmlAst = parseHtmlString(urlInfo.content, {
|
|
28514
|
-
storeOriginalPositions: false
|
|
28515
|
-
});
|
|
28516
|
-
const clientCode = generateClientCodeForGlobals({
|
|
28517
|
-
globals,
|
|
28518
|
-
isWebWorker: false
|
|
28519
|
-
});
|
|
28520
|
-
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
28521
|
-
tagName: "script",
|
|
28522
|
-
textContent: clientCode
|
|
28523
|
-
}), "jsenv:inject_globals");
|
|
28524
|
-
return stringifyHtmlAst(htmlAst);
|
|
28525
|
-
};
|
|
28526
|
-
const globalsInjectorOnJs = async (urlInfo, globals) => {
|
|
28527
|
-
const clientCode = generateClientCodeForGlobals({
|
|
28528
|
-
globals,
|
|
28529
|
-
isWebWorker: urlInfo.subtype === "worker" || urlInfo.subtype === "service_worker" || urlInfo.subtype === "shared_worker"
|
|
28530
|
-
});
|
|
28531
|
-
const magicSource = createMagicSource(urlInfo.content);
|
|
28532
|
-
magicSource.prepend(clientCode);
|
|
28533
|
-
return magicSource.toContentAndSourcemap();
|
|
28534
|
-
};
|
|
28535
|
-
const generateClientCodeForGlobals = ({
|
|
28536
|
-
isWebWorker = false,
|
|
28537
|
-
globals
|
|
28538
|
-
}) => {
|
|
28539
|
-
const globalName = isWebWorker ? "self" : "window";
|
|
28540
|
-
return `Object.assign(${globalName}, ${JSON.stringify(globals, null, " ")});`;
|
|
28541
|
-
};
|
|
28542
|
-
|
|
28543
|
-
const jsenvPluginInjectGlobals = urlAssociations => {
|
|
28544
|
-
return {
|
|
28545
|
-
name: "jsenv:inject_globals",
|
|
28546
|
-
appliesDuring: "*",
|
|
28547
|
-
transformUrlContent: async (urlInfo, context) => {
|
|
28548
|
-
const url = Object.keys(urlAssociations).find(url => {
|
|
28549
|
-
return url === urlInfo.url;
|
|
28550
|
-
});
|
|
28551
|
-
if (!url) {
|
|
28552
|
-
return null;
|
|
28553
|
-
}
|
|
28554
|
-
let globals = urlAssociations[url];
|
|
28555
|
-
if (typeof globals === "function") {
|
|
28556
|
-
globals = await globals(urlInfo, context);
|
|
28557
|
-
}
|
|
28558
|
-
if (Object.keys(globals).length === 0) {
|
|
28559
|
-
return null;
|
|
28560
|
-
}
|
|
28561
|
-
return injectGlobals(urlInfo, globals);
|
|
28562
|
-
}
|
|
28563
|
-
};
|
|
28564
|
-
};
|
|
28565
|
-
|
|
28566
|
-
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, replacePlaceholders, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|
|
28622
|
+
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, jsenvPluginPlaceholders, nodeChildProcess, nodeWorkerThread, pingServer, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "29.
|
|
3
|
+
"version": "29.7.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -69,16 +69,16 @@
|
|
|
69
69
|
"@jsenv/abort": "4.2.4",
|
|
70
70
|
"@jsenv/ast": "1.4.4",
|
|
71
71
|
"@jsenv/babel-plugins": "1.0.9",
|
|
72
|
-
"@jsenv/filesystem": "4.1.
|
|
72
|
+
"@jsenv/filesystem": "4.1.6",
|
|
73
73
|
"@jsenv/importmap": "1.2.1",
|
|
74
74
|
"@jsenv/integrity": "0.0.1",
|
|
75
75
|
"@jsenv/log": "3.3.1",
|
|
76
76
|
"@jsenv/node-esm-resolution": "0.2.0",
|
|
77
77
|
"@jsenv/server": "14.1.9",
|
|
78
|
-
"@jsenv/sourcemap": "1.0.
|
|
78
|
+
"@jsenv/sourcemap": "1.0.7",
|
|
79
79
|
"@jsenv/uneval": "1.6.0",
|
|
80
80
|
"@jsenv/url-meta": "7.0.0",
|
|
81
|
-
"@jsenv/urls": "1.2.
|
|
81
|
+
"@jsenv/urls": "1.2.8",
|
|
82
82
|
"@jsenv/utils": "2.0.1",
|
|
83
83
|
"acorn-import-assertions": "1.8.0",
|
|
84
84
|
"construct-style-sheets-polyfill": "3.1.0",
|
|
@@ -19,6 +19,14 @@ import { defaultRuntimeCompat } from "@jsenv/core/src/build/build.js"
|
|
|
19
19
|
import { createReloadableWorker } from "@jsenv/core/src/helpers/worker_reload.js"
|
|
20
20
|
import { createFileService } from "./file_service.js"
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Start a server for source files:
|
|
24
|
+
* - cook source files according to jsenv plugins
|
|
25
|
+
* - inject code to autoreload the browser when a file is modified
|
|
26
|
+
* @param {Object} devServerParameters
|
|
27
|
+
* @param {string|url} devServerParameters.rootDirectoryUrl Root directory of the project
|
|
28
|
+
* @return {Object} A dev server object
|
|
29
|
+
*/
|
|
22
30
|
export const startDevServer = async ({
|
|
23
31
|
signal = new AbortController().signal,
|
|
24
32
|
handleSIGINT = true,
|
package/src/main.js
CHANGED
|
@@ -23,8 +23,8 @@ export { startBuildServer } from "./build/start_build_server.js"
|
|
|
23
23
|
|
|
24
24
|
// helpers
|
|
25
25
|
export { pingServer } from "./ping_server.js"
|
|
26
|
-
export { replacePlaceholders } from "./helpers/replace_placeholders.js"
|
|
27
26
|
|
|
28
27
|
// advanced
|
|
29
|
-
export { execute } from "./execute/execute.js"
|
|
30
28
|
export { jsenvPluginInjectGlobals } from "./plugins/inject_globals/jsenv_plugin_inject_globals.js"
|
|
29
|
+
export { jsenvPluginPlaceholders } from "./plugins/placeholders/jsenv_plugin_placeholders.js"
|
|
30
|
+
export { execute } from "./execute/execute.js"
|
|
@@ -1,21 +1,33 @@
|
|
|
1
|
+
import { URL_META } from "@jsenv/url-meta"
|
|
2
|
+
import { asUrlWithoutSearch } from "@jsenv/urls"
|
|
3
|
+
|
|
1
4
|
import { injectGlobals } from "./inject_globals.js"
|
|
2
5
|
|
|
3
|
-
export const jsenvPluginInjectGlobals = (
|
|
6
|
+
export const jsenvPluginInjectGlobals = (rawAssociations) => {
|
|
7
|
+
let resolvedAssociations
|
|
8
|
+
|
|
4
9
|
return {
|
|
5
10
|
name: "jsenv:inject_globals",
|
|
6
11
|
appliesDuring: "*",
|
|
12
|
+
init: (context) => {
|
|
13
|
+
resolvedAssociations = URL_META.resolveAssociations(
|
|
14
|
+
{ injector: rawAssociations },
|
|
15
|
+
context.rootDirectoryUrl,
|
|
16
|
+
)
|
|
17
|
+
},
|
|
7
18
|
transformUrlContent: async (urlInfo, context) => {
|
|
8
|
-
const
|
|
9
|
-
|
|
19
|
+
const { injector } = URL_META.applyAssociations({
|
|
20
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
21
|
+
associations: resolvedAssociations,
|
|
10
22
|
})
|
|
11
|
-
if (!
|
|
23
|
+
if (!injector) {
|
|
12
24
|
return null
|
|
13
25
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
globals = await globals(urlInfo, context)
|
|
26
|
+
if (typeof injector !== "function") {
|
|
27
|
+
throw new TypeError("injector must be a function")
|
|
17
28
|
}
|
|
18
|
-
|
|
29
|
+
const globals = await injector(urlInfo, context)
|
|
30
|
+
if (!globals || Object.keys(globals).length === 0) {
|
|
19
31
|
return null
|
|
20
32
|
}
|
|
21
33
|
return injectGlobals(urlInfo, globals)
|
|
@@ -37,6 +37,30 @@ export const jsenvPluginMinification = (minification) => {
|
|
|
37
37
|
options: minification.json,
|
|
38
38
|
})
|
|
39
39
|
: null
|
|
40
|
+
const cssOptimizer = minification.css
|
|
41
|
+
? (urlInfo, context) =>
|
|
42
|
+
minifyCss({
|
|
43
|
+
cssUrlInfo: urlInfo,
|
|
44
|
+
context,
|
|
45
|
+
options: minification.css,
|
|
46
|
+
})
|
|
47
|
+
: null
|
|
48
|
+
const jsClassicOptimizer = minification.js_classic
|
|
49
|
+
? (urlInfo, context) =>
|
|
50
|
+
minifyJs({
|
|
51
|
+
jsUrlInfo: urlInfo,
|
|
52
|
+
context,
|
|
53
|
+
options: minification.js_classic,
|
|
54
|
+
})
|
|
55
|
+
: null
|
|
56
|
+
const jsModuleOptimizer = minification.js_module
|
|
57
|
+
? (urlInfo, context) =>
|
|
58
|
+
minifyJs({
|
|
59
|
+
jsUrlInfo: urlInfo,
|
|
60
|
+
context,
|
|
61
|
+
options: minification.js_module,
|
|
62
|
+
})
|
|
63
|
+
: null
|
|
40
64
|
|
|
41
65
|
return {
|
|
42
66
|
name: "jsenv:minification",
|
|
@@ -44,30 +68,9 @@ export const jsenvPluginMinification = (minification) => {
|
|
|
44
68
|
optimizeUrlContent: {
|
|
45
69
|
html: htmlOptimizer,
|
|
46
70
|
svg: htmlOptimizer,
|
|
47
|
-
css:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
cssUrlInfo: urlInfo,
|
|
51
|
-
context,
|
|
52
|
-
options: minification.css,
|
|
53
|
-
})
|
|
54
|
-
: null,
|
|
55
|
-
js_classic: minification.js_classic
|
|
56
|
-
? (urlInfo, context) =>
|
|
57
|
-
minifyJs({
|
|
58
|
-
jsUrlInfo: urlInfo,
|
|
59
|
-
context,
|
|
60
|
-
options: minification.js_classic,
|
|
61
|
-
})
|
|
62
|
-
: null,
|
|
63
|
-
js_module: minification.js_module
|
|
64
|
-
? (urlInfo, context) =>
|
|
65
|
-
minifyJs({
|
|
66
|
-
jsUrlInfo: urlInfo,
|
|
67
|
-
context,
|
|
68
|
-
options: minification.js_module,
|
|
69
|
-
})
|
|
70
|
-
: null,
|
|
71
|
+
css: cssOptimizer,
|
|
72
|
+
js_classic: jsClassicOptimizer,
|
|
73
|
+
js_module: jsModuleOptimizer,
|
|
71
74
|
json: jsonOptimizer,
|
|
72
75
|
importmap: jsonOptimizer,
|
|
73
76
|
webmanifest: jsonOptimizer,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { URL_META } from "@jsenv/url-meta"
|
|
2
|
+
import { asUrlWithoutSearch } from "@jsenv/urls"
|
|
3
|
+
|
|
4
|
+
import { replacePlaceholders } from "./replace_placeholders.js"
|
|
5
|
+
|
|
6
|
+
export const jsenvPluginPlaceholders = (rawAssociations) => {
|
|
7
|
+
let resolvedAssociations
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: "jsenv:placeholders",
|
|
11
|
+
appliesDuring: "*",
|
|
12
|
+
init: (context) => {
|
|
13
|
+
resolvedAssociations = URL_META.resolveAssociations(
|
|
14
|
+
{ replacer: rawAssociations },
|
|
15
|
+
context.rootDirectoryUrl,
|
|
16
|
+
)
|
|
17
|
+
},
|
|
18
|
+
transformUrlContent: async (urlInfo, context) => {
|
|
19
|
+
const { replacer } = URL_META.applyAssociations({
|
|
20
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
21
|
+
associations: resolvedAssociations,
|
|
22
|
+
})
|
|
23
|
+
if (!replacer) {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
if (typeof replacer !== "function") {
|
|
27
|
+
throw new TypeError("replacer must be a function")
|
|
28
|
+
}
|
|
29
|
+
const replacements = await replacer(urlInfo, context)
|
|
30
|
+
if (!replacements || Object.keys(replacements).length === 0) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
return replacePlaceholders(urlInfo, replacements)
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMagicSource } from "@jsenv/sourcemap"
|
|
2
2
|
|
|
3
|
-
export const replacePlaceholders = (
|
|
3
|
+
export const replacePlaceholders = (urlInfo, replacements) => {
|
|
4
|
+
const content = urlInfo.content
|
|
4
5
|
const magicSource = createMagicSource(content)
|
|
5
6
|
Object.keys(replacements).forEach((key) => {
|
|
6
7
|
let index = content.indexOf(key)
|
|
7
8
|
while (index !== -1) {
|
|
8
9
|
const start = index
|
|
9
10
|
const end = index + key.length
|
|
10
|
-
magicSource.replace({
|
|
11
|
+
magicSource.replace({
|
|
12
|
+
start,
|
|
13
|
+
end,
|
|
14
|
+
replacement:
|
|
15
|
+
urlInfo.type === "js_classic" || urlInfo.type === "js_module"
|
|
16
|
+
? JSON.stringify(replacements[key], null, " ")
|
|
17
|
+
: replacements[key],
|
|
18
|
+
})
|
|
11
19
|
index = content.indexOf(key, end)
|
|
12
20
|
}
|
|
13
21
|
})
|
|
@@ -9,7 +9,7 @@ import { asUrlWithoutSearch } from "@jsenv/urls"
|
|
|
9
9
|
|
|
10
10
|
export const jsenvPluginRibbon = ({
|
|
11
11
|
rootDirectoryUrl,
|
|
12
|
-
htmlInclude = "
|
|
12
|
+
htmlInclude = "/**/*.html",
|
|
13
13
|
}) => {
|
|
14
14
|
const ribbonClientFileUrl = new URL("./client/ribbon.js", import.meta.url)
|
|
15
15
|
const associations = URL_META.resolveAssociations(
|