@jsenv/core 29.9.2 → 30.0.0-alpha.1

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/main.js CHANGED
@@ -15,10 +15,11 @@ import { performance as performance$1 } from "node:perf_hooks";
15
15
  import { Readable, Stream, Writable } from "node:stream";
16
16
  import { Http2ServerResponse } from "node:http2";
17
17
  import { lookup } from "node:dns";
18
- import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, sourcemapConverter, getOriginalPosition } from "@jsenv/sourcemap";
19
- import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, getHtmlNodeText, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
18
+ import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, getOriginalPosition } from "@jsenv/sourcemap";
19
+ import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, getHtmlNodeText, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
20
20
  import { createRequire } from "node:module";
21
21
  import babelParser from "@babel/parser";
22
+ import { bundleJsModules } from "@jsenv/plugin-bundling";
22
23
  import v8, { takeCoverage } from "node:v8";
23
24
  import wrapAnsi from "wrap-ansi";
24
25
  import stripAnsi from "strip-ansi";
@@ -14825,432 +14826,6 @@ const jsenvPluginAsJsClassicWorkers = () => {
14825
14826
  };
14826
14827
  };
14827
14828
 
14828
- /*
14829
- * Generated helpers
14830
- * - https://github.com/babel/babel/commits/main/packages/babel-helpers/src/helpers.ts
14831
- * File helpers
14832
- * - https://github.com/babel/babel/tree/main/packages/babel-helpers/src/helpers
14833
- *
14834
- */
14835
- const babelHelperClientDirectoryUrl = new URL("./babel_helpers/", import.meta.url).href;
14836
-
14837
- // we cannot use "@jsenv/core/src/*" because babel helper might be injected
14838
- // into node_modules not depending on "@jsenv/core"
14839
- const getBabelHelperFileUrl = babelHelperName => {
14840
- const babelHelperFileUrl = new URL(`./${babelHelperName}/${babelHelperName}.js`, babelHelperClientDirectoryUrl).href;
14841
- return babelHelperFileUrl;
14842
- };
14843
- const babelHelperNameFromUrl = url => {
14844
- if (!url.startsWith(babelHelperClientDirectoryUrl)) {
14845
- return null;
14846
- }
14847
- const afterBabelHelperDirectory = url.slice(babelHelperClientDirectoryUrl.length);
14848
- const babelHelperName = afterBabelHelperDirectory.slice(0, afterBabelHelperDirectory.indexOf("/"));
14849
- return babelHelperName;
14850
- };
14851
-
14852
- const fileUrlConverter = {
14853
- asFilePath: fileUrl => {
14854
- const filePath = urlToFileSystemPath(fileUrl);
14855
- const urlObject = new URL(fileUrl);
14856
- const {
14857
- searchParams
14858
- } = urlObject;
14859
- return `${filePath}${stringifyQuery(searchParams)}`;
14860
- },
14861
- asFileUrl: filePath => {
14862
- return decodeURIComponent(fileSystemPathToUrl$1(filePath)).replace(/[=](?=&|$)/g, "");
14863
- }
14864
- };
14865
- const stringifyQuery = searchParams => {
14866
- const search = searchParams.toString();
14867
- return search ? `?${search}` : "";
14868
- };
14869
-
14870
- const globalThisClientFileUrl = new URL("./js/global_this.js", import.meta.url).href;
14871
- const newStylesheetClientFileUrl = new URL("./js/new_stylesheet.js", import.meta.url).href;
14872
- const regeneratorRuntimeClientFileUrl = new URL("./js/regenerator_runtime.js", import.meta.url).href;
14873
- const bundleJsModules = async ({
14874
- jsModuleUrlInfos,
14875
- context,
14876
- options
14877
- }) => {
14878
- const {
14879
- signal,
14880
- logger,
14881
- rootDirectoryUrl,
14882
- buildDirectoryUrl,
14883
- assetsDirectory,
14884
- urlGraph,
14885
- runtimeCompat,
14886
- sourcemaps
14887
- } = context;
14888
- const {
14889
- babelHelpersChunk = true,
14890
- include,
14891
- preserveDynamicImport = false,
14892
- strictExports = false
14893
- } = options;
14894
- const {
14895
- jsModuleBundleUrlInfos
14896
- } = await buildWithRollup({
14897
- signal,
14898
- logger,
14899
- rootDirectoryUrl,
14900
- buildDirectoryUrl,
14901
- assetsDirectory,
14902
- urlGraph,
14903
- jsModuleUrlInfos,
14904
- runtimeCompat,
14905
- sourcemaps,
14906
- include,
14907
- babelHelpersChunk,
14908
- preserveDynamicImport,
14909
- strictExports
14910
- });
14911
- return jsModuleBundleUrlInfos;
14912
- };
14913
- const rollupPluginJsenv = ({
14914
- // logger,
14915
- rootDirectoryUrl,
14916
- buildDirectoryUrl,
14917
- assetsDirectory,
14918
- urlGraph,
14919
- jsModuleUrlInfos,
14920
- sourcemaps,
14921
- include,
14922
- babelHelpersChunk,
14923
- preserveDynamicImport,
14924
- strictExports,
14925
- resultRef
14926
- }) => {
14927
- let _rollupEmitFile = () => {
14928
- throw new Error("not implemented");
14929
- };
14930
- const format = jsModuleUrlInfos.some(jsModuleUrlInfo => jsModuleUrlInfo.filename.endsWith(".cjs")) ? "cjs" : "esm";
14931
- const emitChunk = chunk => {
14932
- return _rollupEmitFile({
14933
- type: "chunk",
14934
- ...chunk
14935
- });
14936
- };
14937
- let importCanBeBundled = () => true;
14938
- if (include) {
14939
- const associations = URL_META.resolveAssociations({
14940
- bundle: include
14941
- }, rootDirectoryUrl);
14942
- importCanBeBundled = url => {
14943
- return URL_META.applyAssociations({
14944
- url,
14945
- associations
14946
- }).bundle;
14947
- };
14948
- }
14949
- const urlImporters = {};
14950
- return {
14951
- name: "jsenv",
14952
- async buildStart() {
14953
- _rollupEmitFile = (...args) => this.emitFile(...args);
14954
- let previousNonEntryPointModuleId;
14955
- jsModuleUrlInfos.forEach(jsModuleUrlInfo => {
14956
- const id = jsModuleUrlInfo.url;
14957
- if (jsModuleUrlInfo.isEntryPoint) {
14958
- emitChunk({
14959
- id
14960
- });
14961
- return;
14962
- }
14963
- emitChunk({
14964
- id,
14965
- implicitlyLoadedAfterOneOf: previousNonEntryPointModuleId ? [previousNonEntryPointModuleId] : null,
14966
- preserveSignature: strictExports ? "strict" : jsModuleUrlInfo.dependents.size < 2 ? "allow-extension" : "strict"
14967
- });
14968
- previousNonEntryPointModuleId = id;
14969
- });
14970
- },
14971
- async generateBundle(outputOptions, rollupResult) {
14972
- _rollupEmitFile = (...args) => this.emitFile(...args);
14973
- const jsModuleBundleUrlInfos = {};
14974
- Object.keys(rollupResult).forEach(fileName => {
14975
- const rollupFileInfo = rollupResult[fileName];
14976
- // there is 3 types of file: "placeholder", "asset", "chunk"
14977
- if (rollupFileInfo.type === "chunk") {
14978
- const sourceUrls = Object.keys(rollupFileInfo.modules).map(id => fileUrlConverter.asFileUrl(id));
14979
- let url;
14980
- let originalUrl;
14981
- if (rollupFileInfo.facadeModuleId) {
14982
- url = fileUrlConverter.asFileUrl(rollupFileInfo.facadeModuleId);
14983
- originalUrl = url;
14984
- } else {
14985
- url = new URL(rollupFileInfo.fileName, buildDirectoryUrl).href;
14986
- if (rollupFileInfo.isDynamicEntry) {
14987
- originalUrl = sourceUrls[sourceUrls.length - 1];
14988
- } else {
14989
- originalUrl = url;
14990
- }
14991
- }
14992
- const jsModuleBundleUrlInfo = {
14993
- url,
14994
- originalUrl,
14995
- type: format === "esm" ? "js_module" : "common_js",
14996
- data: {
14997
- bundlerName: "rollup",
14998
- bundleRelativeUrl: rollupFileInfo.fileName,
14999
- usesImport: rollupFileInfo.imports.length > 0 || rollupFileInfo.dynamicImports.length > 0,
15000
- isDynamicEntry: rollupFileInfo.isDynamicEntry
15001
- },
15002
- sourceUrls,
15003
- contentType: "text/javascript",
15004
- content: rollupFileInfo.code,
15005
- sourcemap: rollupFileInfo.map
15006
- };
15007
- jsModuleBundleUrlInfos[url] = jsModuleBundleUrlInfo;
15008
- }
15009
- });
15010
- resultRef.current = {
15011
- jsModuleBundleUrlInfos
15012
- };
15013
- },
15014
- outputOptions: outputOptions => {
15015
- // const sourcemapFile = buildDirectoryUrl
15016
- Object.assign(outputOptions, {
15017
- format,
15018
- dir: fileUrlConverter.asFilePath(buildDirectoryUrl),
15019
- sourcemap: sourcemaps === "file" || sourcemaps === "inline",
15020
- // sourcemapFile,
15021
- sourcemapPathTransform: relativePath => {
15022
- return new URL(relativePath, buildDirectoryUrl).href;
15023
- },
15024
- entryFileNames: () => {
15025
- return `[name].js`;
15026
- },
15027
- chunkFileNames: chunkInfo => {
15028
- const insideJs = willBeInsideJsDirectory({
15029
- chunkInfo,
15030
- fileUrlConverter,
15031
- jsModuleUrlInfos
15032
- });
15033
- let nameFromUrlInfo;
15034
- if (chunkInfo.facadeModuleId) {
15035
- const url = fileUrlConverter.asFileUrl(chunkInfo.facadeModuleId);
15036
- const urlInfo = jsModuleUrlInfos.find(jsModuleUrlInfo => jsModuleUrlInfo.url === url);
15037
- if (urlInfo) {
15038
- nameFromUrlInfo = urlInfo.filename;
15039
- }
15040
- }
15041
- const name = nameFromUrlInfo || `${chunkInfo.name}.js`;
15042
- return insideJs ? `${assetsDirectory}js/${name}` : `${name}`;
15043
- },
15044
- manualChunks: id => {
15045
- if (babelHelpersChunk) {
15046
- const fileUrl = fileUrlConverter.asFileUrl(id);
15047
- if (fileUrl.endsWith("babel-plugin-transform-async-to-promises/helpers.mjs")) {
15048
- return "babel_helpers";
15049
- }
15050
- if (babelHelperNameFromUrl(fileUrl)) {
15051
- return "babel_helpers";
15052
- }
15053
- if (fileUrl === globalThisClientFileUrl) {
15054
- return "babel_helpers";
15055
- }
15056
- if (fileUrl === newStylesheetClientFileUrl) {
15057
- return "babel_helpers";
15058
- }
15059
- if (fileUrl === regeneratorRuntimeClientFileUrl) {
15060
- return "babel_helpers";
15061
- }
15062
- }
15063
- return null;
15064
- }
15065
- // https://rollupjs.org/guide/en/#outputpaths
15066
- // paths: (id) => {
15067
- // return id
15068
- // },
15069
- });
15070
- },
15071
-
15072
- // https://rollupjs.org/guide/en/#resolvedynamicimport
15073
- resolveDynamicImport: (specifier, importer) => {
15074
- if (preserveDynamicImport) {
15075
- let urlObject;
15076
- if (specifier[0] === "/") {
15077
- urlObject = new URL(specifier.slice(1), rootDirectoryUrl);
15078
- } else {
15079
- if (isFileSystemPath$1(importer)) {
15080
- importer = fileUrlConverter.asFileUrl(importer);
15081
- }
15082
- urlObject = new URL(specifier, importer);
15083
- }
15084
- urlObject.searchParams.set("as_js_classic_library", "");
15085
- return {
15086
- external: true,
15087
- id: urlObject.href
15088
- };
15089
- }
15090
- return null;
15091
- },
15092
- resolveId: (specifier, importer = rootDirectoryUrl) => {
15093
- if (isFileSystemPath$1(importer)) {
15094
- importer = fileUrlConverter.asFileUrl(importer);
15095
- }
15096
- let url;
15097
- if (specifier[0] === "/") {
15098
- url = new URL(specifier.slice(1), rootDirectoryUrl).href;
15099
- } else {
15100
- url = new URL(specifier, importer).href;
15101
- }
15102
- const existingImporter = urlImporters[url];
15103
- if (!existingImporter) {
15104
- urlImporters[url] = importer;
15105
- }
15106
- if (!url.startsWith("file:")) {
15107
- return {
15108
- id: url,
15109
- external: true
15110
- };
15111
- }
15112
- if (!importCanBeBundled(url)) {
15113
- return {
15114
- id: url,
15115
- external: true
15116
- };
15117
- }
15118
- const urlInfo = urlGraph.getUrlInfo(url);
15119
- if (!urlInfo) {
15120
- // happen when excluded by urlAnalysis.include
15121
- return {
15122
- id: url,
15123
- external: true
15124
- };
15125
- }
15126
- if (!urlInfo.shouldHandle) {
15127
- return {
15128
- id: url,
15129
- external: true
15130
- };
15131
- }
15132
- const filePath = fileUrlConverter.asFilePath(url);
15133
- return filePath;
15134
- },
15135
- async load(rollupId) {
15136
- const fileUrl = fileUrlConverter.asFileUrl(rollupId);
15137
- const urlInfo = urlGraph.getUrlInfo(fileUrl);
15138
- return {
15139
- code: urlInfo.content,
15140
- map: (sourcemaps === "file" || sourcemaps === "inline") && urlInfo.sourcemap ? sourcemapConverter.toFilePaths(urlInfo.sourcemap) : null
15141
- };
15142
- }
15143
- };
15144
- };
15145
- const buildWithRollup = async ({
15146
- signal,
15147
- logger,
15148
- rootDirectoryUrl,
15149
- buildDirectoryUrl,
15150
- assetsDirectory,
15151
- urlGraph,
15152
- jsModuleUrlInfos,
15153
- runtimeCompat,
15154
- sourcemaps,
15155
- include,
15156
- babelHelpersChunk,
15157
- preserveDynamicImport
15158
- }) => {
15159
- const resultRef = {
15160
- current: null
15161
- };
15162
- try {
15163
- await applyRollupPlugins({
15164
- rollupPlugins: [rollupPluginJsenv({
15165
- signal,
15166
- logger,
15167
- rootDirectoryUrl,
15168
- buildDirectoryUrl,
15169
- assetsDirectory,
15170
- urlGraph,
15171
- jsModuleUrlInfos,
15172
- runtimeCompat,
15173
- sourcemaps,
15174
- include,
15175
- babelHelpersChunk,
15176
- preserveDynamicImport,
15177
- resultRef
15178
- })],
15179
- inputOptions: {
15180
- input: [],
15181
- onwarn: warning => {
15182
- if (warning.code === "CIRCULAR_DEPENDENCY") {
15183
- return;
15184
- }
15185
- if (warning.code === "THIS_IS_UNDEFINED" && pathToFileURL(warning.id).href === globalThisClientFileUrl) {
15186
- return;
15187
- }
15188
- if (warning.code === "EVAL") {
15189
- // ideally we should disable only for jsenv files
15190
- return;
15191
- }
15192
- logger.warn(String(warning));
15193
- }
15194
- }
15195
- });
15196
- return resultRef.current;
15197
- } catch (e) {
15198
- if (e.code === "MISSING_EXPORT") {
15199
- const detailedMessage = createDetailedMessage$1(e.message, {
15200
- frame: e.frame
15201
- });
15202
- throw new Error(detailedMessage, {
15203
- cause: e
15204
- });
15205
- }
15206
- throw e;
15207
- }
15208
- };
15209
- const applyRollupPlugins = async ({
15210
- rollupPlugins,
15211
- inputOptions = {},
15212
- outputOptions = {}
15213
- }) => {
15214
- const {
15215
- rollup
15216
- } = await import("rollup");
15217
- const {
15218
- importAssertions
15219
- } = await import("acorn-import-assertions");
15220
- const rollupReturnValue = await rollup({
15221
- ...inputOptions,
15222
- plugins: rollupPlugins,
15223
- acornInjectPlugins: [importAssertions, ...(inputOptions.acornInjectPlugins || [])]
15224
- });
15225
- const rollupOutputArray = await rollupReturnValue.generate(outputOptions);
15226
- return rollupOutputArray;
15227
- };
15228
- const willBeInsideJsDirectory = ({
15229
- chunkInfo,
15230
- fileUrlConverter,
15231
- jsModuleUrlInfos
15232
- }) => {
15233
- // if the chunk is generated dynamically by rollup
15234
- // for an entry point jsenv will put that file inside js/ directory
15235
- // if it's generated dynamically for a file already in js/ directory
15236
- // both will be inside the js/ directory
15237
- if (!chunkInfo.facadeModuleId) {
15238
- // generated by rollup
15239
- return true;
15240
- }
15241
- const url = fileUrlConverter.asFileUrl(chunkInfo.facadeModuleId);
15242
- const jsModuleUrlInfo = jsModuleUrlInfos.find(jsModuleUrlInfo => jsModuleUrlInfo.url === url);
15243
- if (!jsModuleUrlInfo) {
15244
- // generated by rollup
15245
- return true;
15246
- }
15247
- if (!jsModuleUrlInfo.isEntryPoint) {
15248
- // not an entry point, jsenv will put it inside js/ directory
15249
- return true;
15250
- }
15251
- return false;
15252
- };
15253
-
15254
14829
  const jsenvPluginAsJsClassicLibrary = ({
15255
14830
  systemJsInjection,
15256
14831
  systemJsClientFileUrl,
@@ -18573,6 +18148,30 @@ const babelPluginInstrument = (api, {
18573
18148
  };
18574
18149
  };
18575
18150
 
18151
+ /*
18152
+ * Generated helpers
18153
+ * - https://github.com/babel/babel/commits/main/packages/babel-helpers/src/helpers.ts
18154
+ * File helpers
18155
+ * - https://github.com/babel/babel/tree/main/packages/babel-helpers/src/helpers
18156
+ *
18157
+ */
18158
+ const babelHelperClientDirectoryUrl = new URL("./babel_helpers/", import.meta.url).href;
18159
+
18160
+ // we cannot use "@jsenv/core/src/*" because babel helper might be injected
18161
+ // into node_modules not depending on "@jsenv/core"
18162
+ const getBabelHelperFileUrl = babelHelperName => {
18163
+ const babelHelperFileUrl = new URL(`./${babelHelperName}/${babelHelperName}.js`, babelHelperClientDirectoryUrl).href;
18164
+ return babelHelperFileUrl;
18165
+ };
18166
+ const babelHelperNameFromUrl = url => {
18167
+ if (!url.startsWith(babelHelperClientDirectoryUrl)) {
18168
+ return null;
18169
+ }
18170
+ const afterBabelHelperDirectory = url.slice(babelHelperClientDirectoryUrl.length);
18171
+ const babelHelperName = afterBabelHelperDirectory.slice(0, afterBabelHelperDirectory.indexOf("/"));
18172
+ return babelHelperName;
18173
+ };
18174
+
18576
18175
  /* eslint-disable camelcase */
18577
18176
  // copied from
18578
18177
  // https://github.com/babel/babel/blob/e498bee10f0123bb208baa228ce6417542a2c3c4/packages/babel-compat-data/data/plugins.json#L1
@@ -19164,10 +18763,10 @@ const babelPluginBabelHelpersAsJsenvImports = (babel, {
19164
18763
  };
19165
18764
  };
19166
18765
 
18766
+ const newStylesheetClientFileUrl = new URL("./js/new_stylesheet.js", import.meta.url).href;
19167
18767
  const babelPluginNewStylesheetAsJsenvImport = (babel, {
19168
18768
  getImportSpecifier
19169
18769
  }) => {
19170
- const newStylesheetClientFileUrl = new URL("./js/new_stylesheet.js", import.meta.url).href;
19171
18770
  return {
19172
18771
  name: "new-stylesheet-as-jsenv-import",
19173
18772
  visitor: {
@@ -19276,10 +18875,10 @@ const getImportAssertionsDescriptor = importAssertions => {
19276
18875
  return importAssertionsDescriptor;
19277
18876
  };
19278
18877
 
18878
+ const globalThisClientFileUrl = new URL("./js/global_this.js", import.meta.url).href;
19279
18879
  const babelPluginGlobalThisAsJsenvImport = (babel, {
19280
18880
  getImportSpecifier
19281
18881
  }) => {
19282
- const globalThisClientFileUrl = new URL("./js/global_this.js", import.meta.url).href;
19283
18882
  return {
19284
18883
  name: "global-this-as-jsenv-import",
19285
18884
  visitor: {
@@ -19307,10 +18906,10 @@ const babelPluginGlobalThisAsJsenvImport = (babel, {
19307
18906
  };
19308
18907
  };
19309
18908
 
18909
+ const regeneratorRuntimeClientFileUrl = new URL("./js/regenerator_runtime.js", import.meta.url).href;
19310
18910
  const babelPluginRegeneratorRuntimeAsJsenvImport = (babel, {
19311
18911
  getImportSpecifier
19312
18912
  }) => {
19313
- const regeneratorRuntimeClientFileUrl = new URL("./js/regenerator_runtime.js", import.meta.url).href;
19314
18913
  return {
19315
18914
  name: "regenerator-runtime-as-jsenv-import",
19316
18915
  visitor: {
@@ -19417,6 +19016,17 @@ const jsenvPluginBabel = ({
19417
19016
  return {
19418
19017
  name: "jsenv:babel",
19419
19018
  appliesDuring: "*",
19019
+ transformUrlContent: urlInfo => {
19020
+ if (urlInfo.url === regeneratorRuntimeClientFileUrl) {
19021
+ urlInfo.data.isBabelClientFile = true;
19022
+ }
19023
+ if (urlInfo.url === globalThisClientFileUrl) {
19024
+ urlInfo.data.isBabelClientFile = true;
19025
+ }
19026
+ if (urlInfo.url === newStylesheetClientFileUrl) {
19027
+ urlInfo.data.isBabelClientFile = true;
19028
+ }
19029
+ },
19420
19030
  finalizeUrlContent: {
19421
19031
  js_classic: transformWithBabel,
19422
19032
  js_module: transformWithBabel
@@ -19609,368 +19219,6 @@ const jsenvPluginNodeRuntime = ({
19609
19219
  };
19610
19220
  };
19611
19221
 
19612
- const sortByDependencies = nodes => {
19613
- const visited = [];
19614
- const sorted = [];
19615
- const circular = [];
19616
- const visit = url => {
19617
- const isSorted = sorted.includes(url);
19618
- if (isSorted) {
19619
- return;
19620
- }
19621
- const isVisited = visited.includes(url);
19622
- if (isVisited) {
19623
- if (!circular.includes(url)) {
19624
- circular.push(url);
19625
- }
19626
- } else {
19627
- visited.push(url);
19628
- nodes[url].dependencies.forEach(dependencyUrl => {
19629
- visit(dependencyUrl);
19630
- });
19631
- sorted.push(url);
19632
- }
19633
- };
19634
- Object.keys(nodes).forEach(url => {
19635
- visit(url);
19636
- });
19637
- sorted.circular = circular;
19638
- return sorted;
19639
- };
19640
-
19641
- /*
19642
- * Each @import found in css is replaced by the file content
19643
- * - There is no need to worry about urls (such as background-image: url())
19644
- * because they are absolute (file://*) and will be made relative again by jsenv build
19645
- * - The sourcemap are not generated but ideally they should be
19646
- * It can be quite challenging, see "bundle_sourcemap.js"
19647
- */
19648
-
19649
- // Do not use until https://github.com/parcel-bundler/parcel-css/issues/181
19650
- const bundleCss = async ({
19651
- cssUrlInfos,
19652
- context
19653
- }) => {
19654
- const bundledCssUrlInfos = {};
19655
- const cssBundleInfos = await performCssBundling({
19656
- cssEntryUrlInfos: cssUrlInfos,
19657
- context
19658
- });
19659
- cssUrlInfos.forEach(cssUrlInfo => {
19660
- bundledCssUrlInfos[cssUrlInfo.url] = {
19661
- data: {
19662
- bundlerName: "parcel"
19663
- },
19664
- contentType: "text/css",
19665
- content: cssBundleInfos[cssUrlInfo.url].bundleContent
19666
- };
19667
- });
19668
- return bundledCssUrlInfos;
19669
- };
19670
- const performCssBundling = async ({
19671
- cssEntryUrlInfos,
19672
- context
19673
- }) => {
19674
- const cssBundleInfos = await loadCssUrls({
19675
- cssEntryUrlInfos,
19676
- context
19677
- });
19678
- const cssUrlsSorted = sortByDependencies(cssBundleInfos);
19679
- cssUrlsSorted.forEach(cssUrl => {
19680
- const cssBundleInfo = cssBundleInfos[cssUrl];
19681
- const magicSource = createMagicSource(cssBundleInfo.content);
19682
- cssBundleInfo.cssUrls.forEach(cssUrl => {
19683
- if (cssUrl.type === "@import") {
19684
- magicSource.replace({
19685
- start: cssUrl.atRuleStart,
19686
- end: cssUrl.atRuleEnd,
19687
- replacement: cssBundleInfos[cssUrl.url].bundleContent
19688
- });
19689
- }
19690
- });
19691
- const {
19692
- content
19693
- } = magicSource.toContentAndSourcemap();
19694
- cssBundleInfo.bundleContent = content.trim();
19695
- });
19696
- return cssBundleInfos;
19697
- };
19698
- const parseCssUrls = async ({
19699
- css,
19700
- url
19701
- }) => {
19702
- const cssUrls = [];
19703
- await applyPostCss({
19704
- sourcemaps: false,
19705
- plugins: [postCssPluginUrlVisitor({
19706
- urlVisitor: ({
19707
- type,
19708
- specifier,
19709
- specifierStart,
19710
- specifierEnd,
19711
- atRuleStart,
19712
- atRuleEnd
19713
- }) => {
19714
- cssUrls.push({
19715
- type,
19716
- url: new URL(specifier, url).href,
19717
- specifierStart,
19718
- specifierEnd,
19719
- atRuleStart,
19720
- atRuleEnd
19721
- });
19722
- }
19723
- })],
19724
- url,
19725
- content: css
19726
- });
19727
- return cssUrls;
19728
- };
19729
- const loadCssUrls = async ({
19730
- cssEntryUrlInfos,
19731
- context
19732
- }) => {
19733
- const cssBundleInfos = {};
19734
- const promises = [];
19735
- const promiseMap = new Map();
19736
- const load = cssUrlInfo => {
19737
- const promiseFromData = promiseMap.get(cssUrlInfo.url);
19738
- if (promiseFromData) return promiseFromData;
19739
- const promise = _load(cssUrlInfo);
19740
- promises.push(promise);
19741
- promiseMap.set(cssUrlInfo.url, promise);
19742
- return promise;
19743
- };
19744
- const _load = async cssUrlInfo => {
19745
- const cssUrls = await parseCssUrls({
19746
- css: cssUrlInfo.content,
19747
- url: cssUrlInfo.url
19748
- });
19749
- const cssBundleInfo = {
19750
- content: cssUrlInfo.content,
19751
- cssUrls,
19752
- dependencies: []
19753
- };
19754
- cssBundleInfos[cssUrlInfo.url] = cssBundleInfo;
19755
- cssUrls.forEach(cssUrl => {
19756
- if (cssUrl.type === "@import") {
19757
- cssBundleInfo.dependencies.push(cssUrl.url);
19758
- const importedCssUrlInfo = context.urlGraph.getUrlInfo(cssUrl.url);
19759
- load(importedCssUrlInfo);
19760
- }
19761
- });
19762
- };
19763
- cssEntryUrlInfos.forEach(cssEntryUrlInfo => {
19764
- load(cssEntryUrlInfo);
19765
- });
19766
- const waitAll = async () => {
19767
- if (promises.length === 0) {
19768
- return;
19769
- }
19770
- const promisesToWait = promises.slice();
19771
- promises.length = 0;
19772
- await Promise.all(promisesToWait);
19773
- await waitAll();
19774
- };
19775
- await waitAll();
19776
- promiseMap.clear();
19777
- return cssBundleInfos;
19778
- };
19779
-
19780
- /*
19781
- * TODO:
19782
- * for each js_classic where subtype is a worker
19783
- * take the url info and find importScripts calls
19784
- * and replace them with the corresponding url info file content
19785
- * we'll ikely need to save the importScripts node location to be able to do that
19786
- */
19787
-
19788
- // import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
19789
-
19790
- const bundleJsClassicWorkers = () => {
19791
- return {};
19792
- };
19793
-
19794
- const jsenvPluginBundling = bundling => {
19795
- if (typeof bundling === "boolean") {
19796
- bundling = {
19797
- css: bundling,
19798
- js_classic_workers: bundling,
19799
- js_module: bundling
19800
- };
19801
- } else if (typeof bundling !== "object") {
19802
- throw new Error(`bundling must be a boolean or an object, got ${bundling}`);
19803
- }
19804
- Object.keys(bundling).forEach(key => {
19805
- if (bundling[key] === true) bundling[key] = {};
19806
- });
19807
- return {
19808
- name: "jsenv:bundling",
19809
- appliesDuring: "build",
19810
- bundle: {
19811
- css: bundling.css ? (cssUrlInfos, context) => {
19812
- return bundleCss({
19813
- cssUrlInfos,
19814
- context,
19815
- options: bundling.css
19816
- });
19817
- } : undefined,
19818
- js_classic: bundling.js_classic ? (jsClassicUrlInfos, context) => {
19819
- return bundleJsClassicWorkers({
19820
- jsClassicUrlInfos,
19821
- context,
19822
- options: bundling.js_classic_workers
19823
- });
19824
- } : undefined,
19825
- js_module: bundling.js_module ? (jsModuleUrlInfos, context) => {
19826
- return bundleJsModules({
19827
- jsModuleUrlInfos,
19828
- context,
19829
- options: bundling.js_module
19830
- });
19831
- } : undefined
19832
- }
19833
- };
19834
- };
19835
-
19836
- // https://github.com/kangax/html-minifier#options-quick-reference
19837
- const minifyHtml = ({
19838
- htmlUrlInfo,
19839
- options
19840
- } = {}) => {
19841
- const {
19842
- collapseWhitespace = true,
19843
- removeComments = true
19844
- } = options;
19845
- const {
19846
- minify
19847
- } = requireFromJsenv("html-minifier");
19848
- const htmlMinified = minify(htmlUrlInfo.content, {
19849
- collapseWhitespace,
19850
- removeComments
19851
- });
19852
- return htmlMinified;
19853
- };
19854
-
19855
- const minifyCss = ({
19856
- cssUrlInfo,
19857
- context
19858
- }) => {
19859
- const {
19860
- code,
19861
- map
19862
- } = minifyWithParcel(cssUrlInfo, context);
19863
- return {
19864
- content: String(code),
19865
- sourcemap: map
19866
- };
19867
- };
19868
-
19869
- // https://github.com/terser-js/terser#minify-options
19870
-
19871
- const minifyJs = async ({
19872
- jsUrlInfo,
19873
- options
19874
- }) => {
19875
- const url = jsUrlInfo.url;
19876
- const content = jsUrlInfo.content;
19877
- const sourcemap = jsUrlInfo.sourcemap;
19878
- const isJsModule = jsUrlInfo.type === "js_module";
19879
- const {
19880
- minify
19881
- } = await import("terser");
19882
- const terserResult = await minify({
19883
- [url]: content
19884
- }, {
19885
- sourceMap: {
19886
- ...(sourcemap ? {
19887
- content: JSON.stringify(sourcemap)
19888
- } : {}),
19889
- asObject: true,
19890
- includeSources: true
19891
- },
19892
- module: isJsModule,
19893
- // We need to preserve "new InlineContent()" calls to be able to recognize them
19894
- // after minification in order to version urls inside inline content text
19895
- keep_fnames: /InlineContent/,
19896
- ...options
19897
- });
19898
- return {
19899
- content: terserResult.code,
19900
- sourcemap: terserResult.map
19901
- };
19902
- };
19903
-
19904
- const minifyJson = ({
19905
- jsonUrlInfo
19906
- }) => {
19907
- const {
19908
- content
19909
- } = jsonUrlInfo;
19910
- if (content.startsWith("{\n")) {
19911
- const jsonWithoutWhitespaces = JSON.stringify(JSON.parse(content));
19912
- return jsonWithoutWhitespaces;
19913
- }
19914
- return null;
19915
- };
19916
-
19917
- const jsenvPluginMinification = minification => {
19918
- if (typeof minification === "boolean") {
19919
- minification = {
19920
- html: minification,
19921
- css: minification,
19922
- js_classic: minification,
19923
- js_module: minification,
19924
- json: minification,
19925
- svg: minification
19926
- };
19927
- } else if (typeof minification !== "object") {
19928
- throw new Error(`minification must be a boolean or an object, got ${minification}`);
19929
- }
19930
- Object.keys(minification).forEach(key => {
19931
- if (minification[key] === true) minification[key] = {};
19932
- });
19933
- const htmlOptimizer = minification.html ? (urlInfo, context) => minifyHtml({
19934
- htmlUrlInfo: urlInfo,
19935
- context,
19936
- options: minification.html
19937
- }) : null;
19938
- const jsonOptimizer = minification.json ? (urlInfo, context) => minifyJson({
19939
- jsonUrlInfo: urlInfo,
19940
- context,
19941
- options: minification.json
19942
- }) : null;
19943
- const cssOptimizer = minification.css ? (urlInfo, context) => minifyCss({
19944
- cssUrlInfo: urlInfo,
19945
- context,
19946
- options: minification.css
19947
- }) : null;
19948
- const jsClassicOptimizer = minification.js_classic ? (urlInfo, context) => minifyJs({
19949
- jsUrlInfo: urlInfo,
19950
- context,
19951
- options: minification.js_classic
19952
- }) : null;
19953
- const jsModuleOptimizer = minification.js_module ? (urlInfo, context) => minifyJs({
19954
- jsUrlInfo: urlInfo,
19955
- context,
19956
- options: minification.js_module
19957
- }) : null;
19958
- return {
19959
- name: "jsenv:minification",
19960
- appliesDuring: "build",
19961
- optimizeUrlContent: {
19962
- html: htmlOptimizer,
19963
- svg: htmlOptimizer,
19964
- css: cssOptimizer,
19965
- js_classic: jsClassicOptimizer,
19966
- js_module: jsModuleOptimizer,
19967
- json: jsonOptimizer,
19968
- importmap: jsonOptimizer,
19969
- webmanifest: jsonOptimizer
19970
- }
19971
- };
19972
- };
19973
-
19974
19222
  // Some "smart" default applied to decide what should hot reload / fullreload:
19975
19223
  // By default:
19976
19224
  // - hot reload on <img src="./image.png" />
@@ -20754,8 +20002,6 @@ const getCorePlugins = ({
20754
20002
  directoryReferenceAllowed,
20755
20003
  supervisor,
20756
20004
  transpilation = true,
20757
- minification = false,
20758
- bundling = false,
20759
20005
  clientMainFileUrl,
20760
20006
  clientAutoreload = false,
20761
20007
  clientFileChangeCallbackList,
@@ -20802,7 +20048,7 @@ const getCorePlugins = ({
20802
20048
  urlResolution
20803
20049
  }), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
20804
20050
  runtimeCompat
20805
- }), jsenvPluginBundling(bundling), jsenvPluginMinification(minification), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({
20051
+ }), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({
20806
20052
  ...clientAutoreload,
20807
20053
  clientFileChangeCallbackList,
20808
20054
  clientFilesPruneCallbackList
@@ -21165,8 +20411,6 @@ const defaultRuntimeCompat = {
21165
20411
  * Directory where asset files will be written
21166
20412
  * @param {string|url} [buildParameters.base=""]
21167
20413
  * Urls in build file contents will be prefixed with this string
21168
- * @param {boolean|object} [buildParameters.minification=true]
21169
- * Minify build file contents
21170
20414
  * @param {boolean} [buildParameters.versioning=true]
21171
20415
  * Controls if url in build file contents are versioned
21172
20416
  * @param {('search_param'|'filename')} [buildParameters.versioningMethod="search_param"]
@@ -21199,8 +20443,6 @@ const build = async ({
21199
20443
  fileSystemMagicRedirection,
21200
20444
  directoryReferenceAllowed,
21201
20445
  transpilation = {},
21202
- bundling = true,
21203
- minification = !runtimeCompat.node,
21204
20446
  versioning = !runtimeCompat.node,
21205
20447
  versioningMethod = "search_param",
21206
20448
  // "filename", "search_param"
@@ -21312,9 +20554,7 @@ build ${entryPointKeys.length} entry points`);
21312
20554
  ...transpilation,
21313
20555
  babelHelpersAsImport: !useExplicitJsClassicConversion,
21314
20556
  jsClassicFallback: false
21315
- },
21316
- minification,
21317
- bundling
20557
+ }
21318
20558
  })],
21319
20559
  sourcemaps,
21320
20560
  sourcemapsSourcesContent,
@@ -22086,7 +21326,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22086
21326
  urlInfo,
22087
21327
  kitchen: finalGraphKitchen,
22088
21328
  versionMappings: versionMappingsNeeded,
22089
- minification
21329
+ minification: plugins.some(plugin => plugin.name === "jsenv:minification")
22090
21330
  });
22091
21331
  });
22092
21332
  }
@@ -22292,8 +21532,15 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22292
21532
  }
22293
21533
  }
22294
21534
  const buildManifest = {};
22295
- const buildFileContents = {};
22296
- const buildInlineContents = {};
21535
+ const buildContents = {};
21536
+ const buildInlineRelativeUrls = [];
21537
+ const getBuildRelativeUrl = url => {
21538
+ const urlObject = new URL(url);
21539
+ urlObject.searchParams.delete("as_js_classic");
21540
+ url = urlObject.href;
21541
+ const buildRelativeUrl = urlToRelativeUrl(url, buildDirectoryUrl);
21542
+ return buildRelativeUrl;
21543
+ };
22297
21544
  GRAPH.forEach(finalGraph, urlInfo => {
22298
21545
  if (!urlInfo.shouldHandle) {
22299
21546
  return;
@@ -22305,21 +21552,35 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
22305
21552
  return;
22306
21553
  }
22307
21554
  if (urlInfo.isInline) {
22308
- const buildRelativeUrl = urlToRelativeUrl(urlInfo.url, buildDirectoryUrl);
22309
- buildInlineContents[buildRelativeUrl] = urlInfo.content;
21555
+ const buildRelativeUrl = getBuildRelativeUrl(urlInfo.url);
21556
+ buildContents[buildRelativeUrl] = urlInfo.content;
21557
+ buildInlineRelativeUrls.push(buildRelativeUrl);
22310
21558
  } else {
22311
21559
  const versionedUrl = versionedUrlMap.get(urlInfo.url);
22312
21560
  if (versionedUrl && canUseVersionedUrl(urlInfo)) {
22313
- const buildRelativeUrl = urlToRelativeUrl(urlInfo.url, buildDirectoryUrl);
22314
- const versionedBuildRelativeUrl = urlToRelativeUrl(versionedUrl, buildDirectoryUrl);
22315
- buildFileContents[versionedBuildRelativeUrl] = urlInfo.content;
21561
+ const buildRelativeUrl = getBuildRelativeUrl(urlInfo.url);
21562
+ const versionedBuildRelativeUrl = getBuildRelativeUrl(versionedUrl);
21563
+ if (versioningMethod === "search_param") {
21564
+ buildContents[buildRelativeUrl] = urlInfo.content;
21565
+ } else {
21566
+ buildContents[versionedBuildRelativeUrl] = urlInfo.content;
21567
+ }
22316
21568
  buildManifest[buildRelativeUrl] = versionedBuildRelativeUrl;
22317
21569
  } else {
22318
- const buildRelativeUrl = urlToRelativeUrl(urlInfo.url, buildDirectoryUrl);
22319
- buildFileContents[buildRelativeUrl] = urlInfo.content;
21570
+ const buildRelativeUrl = getBuildRelativeUrl(urlInfo.url);
21571
+ buildContents[buildRelativeUrl] = urlInfo.content;
22320
21572
  }
22321
21573
  }
22322
21574
  });
21575
+ const buildFileContents = {};
21576
+ const buildInlineContents = {};
21577
+ Object.keys(buildContents).sort((a, b) => comparePathnames(a, b)).forEach(buildRelativeUrl => {
21578
+ if (buildInlineRelativeUrls.includes(buildRelativeUrl)) {
21579
+ buildInlineContents[buildRelativeUrl] = buildContents[buildRelativeUrl];
21580
+ } else {
21581
+ buildFileContents[buildRelativeUrl] = buildContents[buildRelativeUrl];
21582
+ }
21583
+ });
22323
21584
  if (writeOnFileSystem) {
22324
21585
  if (directoryToClean) {
22325
21586
  await ensureEmptyDirectory(directoryToClean);