@jsenv/core 41.4.26 → 41.4.28

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.
@@ -1,7 +1,7 @@
1
1
  import { WebSocketResponse, pickContentType, ServerEvents, serverPluginErrorHandler, fetchDirectory, composeTwoResponses, serverPluginCORS, jsenvAccessControlAllowedHeaders, startServer } from "@jsenv/server";
2
2
  import { existsSync, readFileSync, realpathSync, readdirSync, lstatSync, statSync } from "node:fs";
3
3
  import { pathToFileURL } from "node:url";
4
- import { urlToRelativeUrl, registerFileLifecycle, lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, errorToHTML, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, URL_META, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, collectFiles, registerDirectoryLifecycle, readEntryStatSync, applyFileSystemMagicResolution, getExtensionsToTry, urlToFilename, asUrlWithoutSearch, ensurePathnameTrailingSlash, compareFileUrls, setUrlExtension, createDetailedMessage, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT, formatError, assertAndNormalizeDirectoryUrl, createTaskLog } from "./jsenv_core_packages.js";
4
+ import { urlToRelativeUrl, registerFileLifecycle, lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, errorToHTML, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, URL_META, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, collectFiles, registerDirectoryLifecycle, readEntryStatSync, applyFileSystemMagicResolution, getExtensionsToTry, urlToFilename, asUrlWithoutSearch, ensurePathnameTrailingSlash, compareFileUrls, setUrlExtension, createDetailedMessage, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT, formatError, assertAndNormalizeDirectoryUrl, browserDefaultRuntimeCompat, inferRuntimeCompatFromClosestPackage, createTaskLog } from "./jsenv_core_packages.js";
5
5
  import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
6
6
  import { parseHtml, injectJsenvScript, stringifyHtmlAst, parseCssUrls, getHtmlNodeAttribute, getHtmlNodePosition, getHtmlNodeAttributePosition, setHtmlNodeAttributes, parseSrcSet, getUrlForContentInsideHtml, removeHtmlNodeText, setHtmlNodeText, getHtmlNodeText, analyzeScriptNode, visitHtmlNodes, parseJsUrls, getUrlForContentInsideJs, renderCssTemplateLiteral, applyBabelPlugins, visitJsAst, getImportMetaPropertyName, visitJsAstUntil, analyzeLinkNode, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn } from "@jsenv/ast";
7
7
  import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
@@ -17,20 +17,6 @@ import "node:tty";
17
17
  import "node:util";
18
18
  import "node:path";
19
19
 
20
- // default runtimeCompat corresponds to
21
- // "we can keep <script type="module"> intact":
22
- // so script_type_module + dynamic_import + import_meta
23
- const defaultRuntimeCompat = {
24
- // android: "8",
25
- chrome: "64",
26
- edge: "79",
27
- firefox: "67",
28
- ios: "12",
29
- opera: "51",
30
- safari: "11.3",
31
- samsung: "9.2",
32
- };
33
-
34
20
  const createEventEmitter = () => {
35
21
  const callbackSet = new Set();
36
22
  const on = (callback) => {
@@ -6179,6 +6165,12 @@ const jsenvPluginImportMetaCss = () => {
6179
6165
  return null;
6180
6166
  }
6181
6167
  if (urlInfo.context.build) {
6168
+ if (hasModuleScopeAssignment(urlInfo.contentAst)) {
6169
+ urlInfo.contentSideEffects.push({
6170
+ has: true,
6171
+ reason: "import.meta.css assigned at module scope",
6172
+ });
6173
+ }
6182
6174
  const packageName = urlInfo.packageName;
6183
6175
  const packageDirectoryUrl =
6184
6176
  urlInfo.packageDirectoryUrl || urlInfo.context.rootDirectoryUrl;
@@ -6222,6 +6214,28 @@ const jsenvPluginImportMetaCss = () => {
6222
6214
  };
6223
6215
  };
6224
6216
 
6217
+ // A stylesheet assigned at module scope is adopted when the module runs: that
6218
+ // assignment IS the module's side effect. It has to be told, because a
6219
+ // package.json "sideEffects" list is authoritative once it exists — a module
6220
+ // it does not name is dropped whole when it is imported for nothing else, and
6221
+ // its css silently leaves the build.
6222
+ const hasModuleScopeAssignment = (ast) => {
6223
+ for (const node of ast.body) {
6224
+ if (node.type !== "ExpressionStatement") {
6225
+ continue;
6226
+ }
6227
+ const { expression } = node;
6228
+ if (
6229
+ expression.type === "AssignmentExpression" &&
6230
+ expression.operator === "=" &&
6231
+ getImportMetaPropertyName(expression.left) === "css"
6232
+ ) {
6233
+ return true;
6234
+ }
6235
+ }
6236
+ return false;
6237
+ };
6238
+
6225
6239
  const babelPluginRewriteImportMetaCssAssignment = (
6226
6240
  { types: t },
6227
6241
  { relativeUrl },
@@ -12093,10 +12107,11 @@ const startDevServer = async ({
12093
12107
  // a test wants them all, hence 0 there.
12094
12108
  serverTiming = { minDuration: EXECUTED_BY_TEST_PLAN ? 0 : 0.5 },
12095
12109
 
12096
- // runtimeCompat is the runtimeCompat for the build
12097
- // when specified, dev server use it to warn in case
12098
- // code would be supported during dev but not after build
12099
- runtimeCompat = defaultRuntimeCompat,
12110
+ // The runtimeCompat the build will use: the dev server warns when code works
12111
+ // in dev but would not survive that build, and transpiles what those runtimes
12112
+ // lack. Left out, it is inferred exactly as build() infers it, so the two
12113
+ // never disagree on what they target.
12114
+ runtimeCompat,
12100
12115
  plugins = [],
12101
12116
  referenceAnalysis = {},
12102
12117
  nodeEsmResolution,
@@ -12167,6 +12182,12 @@ const startDevServer = async ({
12167
12182
  }
12168
12183
  // params normalization
12169
12184
  {
12185
+ if (runtimeCompat === undefined) {
12186
+ runtimeCompat =
12187
+ (await inferRuntimeCompatFromClosestPackage(sourceDirectoryUrl, {
12188
+ runtimeType: "browser",
12189
+ })) || browserDefaultRuntimeCompat;
12190
+ }
12170
12191
  if (clientAutoreload === true) {
12171
12192
  clientAutoreload = {};
12172
12193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "41.4.26",
3
+ "version": "41.4.28",
4
4
  "type": "module",
5
5
  "description": "Tool to develop, test and build js projects",
6
6
  "repository": {
@@ -78,7 +78,7 @@
78
78
  "@jsenv/plugin-bundling": "2.10.18",
79
79
  "@jsenv/plugin-minification": "1.7.11",
80
80
  "@jsenv/plugin-supervisor": "1.8.14",
81
- "@jsenv/plugin-transpilation": "1.6.3",
81
+ "@jsenv/plugin-transpilation": "1.6.4",
82
82
  "@jsenv/server": "17.6.3",
83
83
  "@jsenv/sourcemap": "1.4.2",
84
84
  "react-table": "7.8.0"
@@ -70,7 +70,7 @@ import { isBareSpecifier } from "../helpers/bare_specifier.js";
70
70
  import { getCorePlugins } from "../plugins/plugins.js";
71
71
  import { jsenvPluginReferenceAnalysis } from "../plugins/reference_analysis/jsenv_plugin_reference_analysis.js";
72
72
  import { renderBuildDoneLog } from "./build_content_report.js";
73
- import { defaultRuntimeCompat, logsDefault } from "./build_params.js";
73
+ import { logsDefault } from "./build_params.js";
74
74
  import { createBuildSpecifierManager } from "./build_specifier_manager.js";
75
75
  import { createBuildUrlsGenerator } from "./build_urls_generator.js";
76
76
  import { jsenvPluginLineBreakNormalization } from "./jsenv_plugin_line_break_normalization.js";
@@ -981,7 +981,7 @@ entryPoints: {
981
981
  const entryPointDefaultParams = {
982
982
  buildRelativeUrl: undefined,
983
983
  mode: undefined,
984
- runtimeCompat: defaultRuntimeCompat,
984
+ runtimeCompat: undefined,
985
985
  plugins: [],
986
986
  mappings: undefined,
987
987
  assetsDirectory: undefined,
@@ -1,16 +1,3 @@
1
- // default runtimeCompat corresponds to
2
- // "we can keep <script type="module"> intact":
3
- // so script_type_module + dynamic_import + import_meta
4
- export const defaultRuntimeCompat = {
5
- // android: "8",
6
- chrome: "64",
7
- edge: "79",
8
- firefox: "67",
9
- ios: "12",
10
- opera: "51",
11
- safari: "11.3",
12
- samsung: "9.2",
13
- };
14
1
  export const logsDefault = {
15
2
  level: "info",
16
3
  animated: true,
@@ -13,10 +13,13 @@ import {
13
13
  urlToFileSystemPath,
14
14
  urlToRelativeUrl,
15
15
  } from "@jsenv/urls";
16
+ import {
17
+ browserDefaultRuntimeCompat,
18
+ inferRuntimeCompatFromClosestPackage,
19
+ } from "@jsenv/runtime-compat";
16
20
  import { existsSync } from "node:fs";
17
21
  import { pathToFileURL } from "node:url";
18
22
 
19
- import { defaultRuntimeCompat } from "../build/build_params.js";
20
23
  import { createEventEmitter } from "../helpers/event_emitter.js";
21
24
  import { watchDependencies } from "../helpers/watch_dependencies.js";
22
25
  import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
@@ -104,10 +107,11 @@ export const startDevServer = async ({
104
107
  // a test wants them all, hence 0 there.
105
108
  serverTiming = { minDuration: EXECUTED_BY_TEST_PLAN ? 0 : 0.5 },
106
109
 
107
- // runtimeCompat is the runtimeCompat for the build
108
- // when specified, dev server use it to warn in case
109
- // code would be supported during dev but not after build
110
- runtimeCompat = defaultRuntimeCompat,
110
+ // The runtimeCompat the build will use: the dev server warns when code works
111
+ // in dev but would not survive that build, and transpiles what those runtimes
112
+ // lack. Left out, it is inferred exactly as build() infers it, so the two
113
+ // never disagree on what they target.
114
+ runtimeCompat,
111
115
  plugins = [],
112
116
  referenceAnalysis = {},
113
117
  nodeEsmResolution,
@@ -179,6 +183,12 @@ export const startDevServer = async ({
179
183
  }
180
184
  // params normalization
181
185
  {
186
+ if (runtimeCompat === undefined) {
187
+ runtimeCompat =
188
+ (await inferRuntimeCompatFromClosestPackage(sourceDirectoryUrl, {
189
+ runtimeType: "browser",
190
+ })) || browserDefaultRuntimeCompat;
191
+ }
182
192
  if (clientAutoreload === true) {
183
193
  clientAutoreload = {};
184
194
  }
@@ -64,6 +64,12 @@ export const jsenvPluginImportMetaCss = () => {
64
64
  return null;
65
65
  }
66
66
  if (urlInfo.context.build) {
67
+ if (hasModuleScopeAssignment(urlInfo.contentAst)) {
68
+ urlInfo.contentSideEffects.push({
69
+ has: true,
70
+ reason: "import.meta.css assigned at module scope",
71
+ });
72
+ }
67
73
  const packageName = urlInfo.packageName;
68
74
  const packageDirectoryUrl =
69
75
  urlInfo.packageDirectoryUrl || urlInfo.context.rootDirectoryUrl;
@@ -107,6 +113,28 @@ export const jsenvPluginImportMetaCss = () => {
107
113
  };
108
114
  };
109
115
 
116
+ // A stylesheet assigned at module scope is adopted when the module runs: that
117
+ // assignment IS the module's side effect. It has to be told, because a
118
+ // package.json "sideEffects" list is authoritative once it exists — a module
119
+ // it does not name is dropped whole when it is imported for nothing else, and
120
+ // its css silently leaves the build.
121
+ const hasModuleScopeAssignment = (ast) => {
122
+ for (const node of ast.body) {
123
+ if (node.type !== "ExpressionStatement") {
124
+ continue;
125
+ }
126
+ const { expression } = node;
127
+ if (
128
+ expression.type === "AssignmentExpression" &&
129
+ expression.operator === "=" &&
130
+ getImportMetaPropertyName(expression.left) === "css"
131
+ ) {
132
+ return true;
133
+ }
134
+ }
135
+ return false;
136
+ };
137
+
110
138
  const babelPluginRewriteImportMetaCssAssignment = (
111
139
  { types: t },
112
140
  { relativeUrl },