diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 725240a6bb..c380436e1a 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -70,6 +70,7 @@ const eslintConfig = composeEslintConfig( __filename: "off", __dirname: "off", require: "off", + exports: "off", }, overrides: [ { @@ -82,6 +83,7 @@ const eslintConfig = composeEslintConfig( __filename: true, __dirname: true, require: true, + exports: true, }, // inside *.cjs files, use commonjs module resolution settings: { diff --git a/experimental/commonjs_with_babel/convert_commonjs.js b/experimental/commonjs_with_babel/convert_commonjs.js index 3bc32a7c7f..15dd133f4f 100644 --- a/experimental/commonjs_with_babel/convert_commonjs.js +++ b/experimental/commonjs_with_babel/convert_commonjs.js @@ -1,5 +1,7 @@ +// eslint-disable-next-line no-undef exports.answer = process.env.NODE_ENV +// eslint-disable-next-line no-undef exports.setTimeout = global.setTimeout // eslint-disable-next-line no-undef diff --git a/jsconfig.json b/jsconfig.json index 06ab1f6aec..fc7db87a6c 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -318,7 +318,7 @@ "./node_modules/cssnano-preset-default/*" ], "istanbul-lib-instrument": [ - "./node_modules/istanbul-lib-instrument/dist/index.js" + "./node_modules/istanbul-lib-instrument/src/index.js" ], "postcss/lib/declaration": [ "./node_modules/postcss/lib/declaration.js" diff --git a/package.json b/package.json index 1f68f70c73..60911ae0e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@jsenv/core", - "version": "21.0.3", + "version": "21.1.0", "description": "Tool to develop, test and build js projects", "license": "MIT", "repository": { @@ -57,7 +57,7 @@ "@babel/core": "7.15.5", "@babel/helper-module-imports": "7.15.4", "@babel/helpers": "7.15.4", - "@babel/parser": "7.15.6", + "@babel/parser": "7.15.7", "@babel/plugin-proposal-dynamic-import": "7.14.5", "@babel/plugin-proposal-json-strings": "7.14.5", "@babel/plugin-proposal-numeric-separator": "7.14.5", @@ -95,15 +95,15 @@ "@babel/plugin-transform-unicode-regex": "7.14.5", "@c88/v8-coverage": "0.1.1", "@jsenv/cancellation": "3.0.0", - "@jsenv/filesystem": "2.1.1", + "@jsenv/filesystem": "2.2.0", "@jsenv/import-map": "6.13.3", "@jsenv/logger": "4.0.1", "@jsenv/node-signals": "2.0.1", - "@jsenv/server": "7.1.0", + "@jsenv/server": "7.2.0", "@jsenv/uneval": "1.6.0", "@rollup/plugin-commonjs": "20.0.0", "@rollup/plugin-json": "4.1.0", - "@rollup/plugin-node-resolve": "13.0.4", + "@rollup/plugin-node-resolve": "13.0.5", "@rollup/plugin-replace": "3.0.0", "ansi-to-html": "0.7.1", "babel-plugin-transform-async-to-promises": "0.8.15", @@ -115,49 +115,49 @@ "html-minifier": "4.0.0", "humanize-duration": "3.27.0", "is-unicode-supported": "1.1.0", - "istanbul-lib-coverage": "3.0.0", - "istanbul-lib-instrument": "4.0.3", + "istanbul-lib-coverage": "3.0.1", + "istanbul-lib-instrument": "5.0.2", "istanbul-lib-report": "3.0.0", "istanbul-reports": "3.0.2", "magic-string": "0.25.7", "parse5": "6.0.1", - "playwright": "1.14.1", - "postcss": "8.3.6", + "playwright": "1.15.0", + "postcss": "8.3.8", "postcss-value-parser": "4.1.0", "regenerator-runtime": "0.13.9", - "rollup": "2.56.3", + "rollup": "2.57.0", "rollup-plugin-node-builtins-brofs": "2.1.3", "rollup-plugin-node-globals": "1.4.0", "source-map": "0.7.3", - "string-width": "5.0.0", + "string-width": "5.0.1", "supports-color": "9.0.2", "systemjs": "6.10.3", - "terser": "5.7.2", + "terser": "5.9.0", "tree-kill": "1.2.2", - "v8-to-istanbul": "8.0.0", - "wrap-ansi": "8.0.0" + "v8-to-istanbul": "8.1.0", + "wrap-ansi": "8.0.1" }, "devDependencies": { - "@babel/eslint-parser": "7.15.4", + "@babel/eslint-parser": "7.15.7", "@babel/plugin-transform-react-jsx": "7.14.9", "@babel/plugin-transform-typescript": "7.15.4", "@jsenv/assert": "2.3.1", "@jsenv/codecov-upload": "3.5.0", - "@jsenv/eslint-config": "16.0.1", + "@jsenv/eslint-config": "16.0.4", "@jsenv/github-release-package": "1.2.3", "@jsenv/importmap-eslint-resolver": "5.1.2", - "@jsenv/importmap-node-module": "2.2.0", + "@jsenv/importmap-node-module": "2.2.1", "@jsenv/node-module-import-map": "13.6.1", "@jsenv/package-publish": "1.6.2", "@jsenv/performance-impact": "1.7.0", "@jsenv/prettier-check-project": "5.6.1", "@jsenv/pwa": "4.0.0", "eslint": "7.32.0", - "eslint-plugin-html": "6.1.2", + "eslint-plugin-html": "6.2.0", "eslint-plugin-import": "2.24.2", "node-notifier": "10.0.0", "preact": "10.5.14", - "prettier": "2.4.0", + "prettier": "2.4.1", "react": "17.0.2", "redux": "4.1.1" } diff --git a/src/commonJsToJavaScriptModule.js b/src/commonJsToJavaScriptModule.js index d82779ef2c..846cbee30b 100644 --- a/src/commonJsToJavaScriptModule.js +++ b/src/commonJsToJavaScriptModule.js @@ -60,7 +60,11 @@ export const commonJsToJavaScriptModule = async ({ buffer: replaceBuffer, }) - const commonJsRollupPlugin = commonjs() + const commonJsRollupPlugin = commonjs({ + // esmExternals: true, + // defaultIsModuleExports: true, + // requireReturnsDefault: "namespace", + }) const rollupBuild = await rollup({ input: filePath, diff --git a/src/internal/building/buildUsingRollup.js b/src/internal/building/buildUsingRollup.js index 9a394103ec..ec630156c3 100644 --- a/src/internal/building/buildUsingRollup.js +++ b/src/internal/building/buildUsingRollup.js @@ -1,5 +1,11 @@ import { createOperation } from "@jsenv/cancellation" -import { urlToFileSystemPath, ensureEmptyDirectory } from "@jsenv/filesystem" +import { + urlToFileSystemPath, + ensureEmptyDirectory, + readFile, + urlToRelativeUrl, +} from "@jsenv/filesystem" +import { createDetailedMessage } from "@jsenv/logger" import { buildServiceWorker } from "@jsenv/core/src/internal/building/buildServiceWorker.js" import { createJsenvRollupPlugin } from "./createJsenvRollupPlugin.js" @@ -61,45 +67,50 @@ export const buildUsingRollup = async ({ runtimeSupport.safari, ) - const { jsenvRollupPlugin, getLastErrorMessage, getResult } = - await createJsenvRollupPlugin({ - cancellationToken, - logger, + const { + jsenvRollupPlugin, + getLastErrorMessage, + getResult, + asOriginalUrl, + asProjectUrl, + } = await createJsenvRollupPlugin({ + cancellationToken, + logger, - projectDirectoryUrl, - entryPointMap, - compileServerOrigin, - compileDirectoryRelativeUrl, - buildDirectoryUrl, - assetManifestFile, - assetManifestFileRelativeUrl, - writeOnFileSystem, + projectDirectoryUrl, + entryPointMap, + compileServerOrigin, + compileDirectoryRelativeUrl, + buildDirectoryUrl, + assetManifestFile, + assetManifestFileRelativeUrl, + writeOnFileSystem, - format, - systemJsUrl, - babelPluginMap, - transformTopLevelAwait, - node, - browser, - - urlMappings, - importResolutionMethod, - importMapFileRelativeUrl, - importDefaultExtension, - externalImportSpecifiers, - externalImportUrlPatterns, - importPaths, - - urlVersioning, - lineBreakNormalization, - jsConcatenation, - useImportMapToMaximizeCacheReuse, - - minify, - minifyJsOptions, - minifyCssOptions, - minifyHtmlOptions, - }) + format, + systemJsUrl, + babelPluginMap, + transformTopLevelAwait, + node, + browser, + + urlMappings, + importResolutionMethod, + importMapFileRelativeUrl, + importDefaultExtension, + externalImportSpecifiers, + externalImportUrlPatterns, + importPaths, + + urlVersioning, + lineBreakNormalization, + jsConcatenation, + useImportMapToMaximizeCacheReuse, + + minify, + minifyJsOptions, + minifyCssOptions, + minifyHtmlOptions, + }) try { await useRollup({ @@ -123,6 +134,25 @@ export const buildUsingRollup = async ({ } throw e } + if (e.code === "MISSING_EXPORT") { + let message = e.message + message = message.replace(e.id, (url) => asOriginalUrl(url)) + message = message.replace(/(www|http:|https:)+[^\s]+[\w]/g, (url) => + asOriginalUrl(url), + ) + const importedFileRollupUrl = e.message.match(/not exported by (.*?),/)[1] + const convertSuggestion = await getConvertSuggestion({ + importedFileRollupUrl, + asProjectUrl, + asOriginalUrl, + projectDirectoryUrl, + }) + const detailedMessage = createDetailedMessage(message, { + frame: e.frame, + ...convertSuggestion, + }) + throw new Error(detailedMessage, { cause: e }) + } throw e } @@ -248,3 +278,33 @@ const formatToRollupFormat = (format) => { if (format === "esmodule") return "esm" throw new Error(`unexpected format, got ${format}`) } + +const getConvertSuggestion = async ({ + importedFileRollupUrl, + asProjectUrl, + asOriginalUrl, + projectDirectoryUrl, +}) => { + const importedFileUrl = asProjectUrl(importedFileRollupUrl) + const importedFileContent = await readFile(importedFileUrl) + const looksLikeCommonJs = + importedFileContent.includes("module.exports = ") || + importedFileContent.includes("exports.") + + if (!looksLikeCommonJs) { + return null + } + + const importerFileOriginalUrl = asOriginalUrl(importedFileUrl) + const importedFileOriginalRelativeUrl = urlToRelativeUrl( + importerFileOriginalUrl, + projectDirectoryUrl, + ) + return { + suggestion: `The file seems written in commonjs, you should use "customCompiler" to convert it to js module +{ + "./${importedFileOriginalRelativeUrl}": commonJsToJavaScriptModule +} +As documented in https://github.com/jsenv/jsenv-core/blob/master/docs/shared-parameters.md#customcompilers`, + } +} diff --git a/src/internal/building/createJsenvRollupPlugin.js b/src/internal/building/createJsenvRollupPlugin.js index af6c9ac5c8..33f1929c68 100644 --- a/src/internal/building/createJsenvRollupPlugin.js +++ b/src/internal/building/createJsenvRollupPlugin.js @@ -167,6 +167,8 @@ export const createJsenvRollupPlugin = async ({ let ressourceBuilder let rollupEmitFile = () => {} let rollupSetAssetSource = () => {} + let _rollupGetModuleInfo = () => {} + const rollupGetModuleInfo = (id) => _rollupGetModuleInfo(id) let importResolver const emitAsset = ({ fileName, source }) => { @@ -228,6 +230,7 @@ building ${entryFileRelativeUrls.length} entry files...`) // https://rollupjs.org/guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string rollupEmitFile = (...args) => this.emitFile(...args) rollupSetAssetSource = (...args) => this.setAssetSource(...args) + _rollupGetModuleInfo = (id) => this.getModuleInfo(id) let importMapInfoFromHtml = null if (htmlEntryPointCount === 1) { @@ -1176,6 +1179,9 @@ non-js ressources can be used with new URL("${urlRelativeToImporter}", import.me buildStats, } }, + asOriginalUrl, + asProjectUrl, + rollupGetModuleInfo, } } diff --git a/test/async-await/async-await-build-commonjs-untransformed/async-await-build-commonjs-untransformed.js b/test/async_await/async_await.js similarity index 100% rename from test/async-await/async-await-build-commonjs-untransformed/async-await-build-commonjs-untransformed.js rename to test/async_await/async_await.js diff --git a/test/build_async_await_commonjs/build_async_await_commonjs.test.js b/test/async_await/async_await_build_commonjs.test.js similarity index 82% rename from test/build_async_await_commonjs/build_async_await_commonjs.test.js rename to test/async_await/async_await_build_commonjs.test.js index 026b28b0a9..81e9654dd6 100644 --- a/test/build_async_await_commonjs/build_async_await_commonjs.test.js +++ b/test/async_await/async_await_build_commonjs.test.js @@ -1,9 +1,5 @@ import { assert } from "@jsenv/assert" -import { - resolveDirectoryUrl, - urlToRelativeUrl, - urlToBasename, -} from "@jsenv/filesystem" +import { resolveDirectoryUrl, urlToRelativeUrl } from "@jsenv/filesystem" import { buildProject } from "@jsenv/core" import { jsenvCoreDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js" @@ -18,13 +14,11 @@ const testDirectoryRelativeUrl = urlToRelativeUrl( testDirectoryUrl, jsenvCoreDirectoryUrl, ) -const testDirectoryname = urlToBasename(testDirectoryRelativeUrl) const jsenvDirectoryRelativeUrl = `${testDirectoryRelativeUrl}.jsenv` const buildDirectoryRelativeUrl = `${testDirectoryRelativeUrl}dist/commonjs` const entryPointMap = { - [`./${testDirectoryRelativeUrl}${testDirectoryname}.js`]: "./main.cjs", + [`./${testDirectoryRelativeUrl}async_await.js`]: "./main.cjs", } - await buildProject({ ...GENERATE_COMMONJS_BUILD_TEST_PARAMS, jsenvDirectoryRelativeUrl, diff --git a/test/async-await/async-await-build-commonjs-untransformed/async-await-build-commonjs-untransformed.test.js b/test/async_await/async_await_build_commonjs_untransformed.test.js similarity index 78% rename from test/async-await/async-await-build-commonjs-untransformed/async-await-build-commonjs-untransformed.test.js rename to test/async_await/async_await_build_commonjs_untransformed.test.js index 8c8168fd23..610b553253 100644 --- a/test/async-await/async-await-build-commonjs-untransformed/async-await-build-commonjs-untransformed.test.js +++ b/test/async_await/async_await_build_commonjs_untransformed.test.js @@ -1,6 +1,6 @@ -import { basename } from "path" import { assert } from "@jsenv/assert" import { resolveUrl, urlToRelativeUrl } from "@jsenv/filesystem" + import { buildProject } from "@jsenv/core" import { jsenvCoreDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js" import { requireCommonJsBuild } from "@jsenv/core/test/requireCommonJsBuild.js" @@ -14,14 +14,11 @@ const testDirectoryRelativeUrl = urlToRelativeUrl( testDirectoryUrl, jsenvCoreDirectoryUrl, ) -const testDirectoryname = basename(testDirectoryRelativeUrl) const jsenvDirectoryRelativeUrl = `${testDirectoryRelativeUrl}.jsenv` const buildDirectoryRelativeUrl = `${testDirectoryRelativeUrl}dist/commonjs` -const mainFilename = `${testDirectoryname}.js` const entryPointMap = { - [`./${testDirectoryRelativeUrl}${mainFilename}`]: "./main.cjs", + [`./${testDirectoryRelativeUrl}async_await.js`]: "./main.cjs", } - await buildProject({ ...GENERATE_COMMONJS_BUILD_TEST_PARAMS, babelPluginMap: {}, @@ -29,12 +26,11 @@ await buildProject({ buildDirectoryRelativeUrl, entryPointMap, }) -const { - namespace: { ask }, -} = await requireCommonJsBuild({ +const { namespace } = await requireCommonJsBuild({ ...REQUIRE_COMMONJS_BUILD_TEST_PARAMS, buildDirectoryRelativeUrl, }) -const actual = await ask() + +const actual = await namespace.ask() const expected = 42 assert({ actual, expected }) diff --git a/test/build_async_await_commonjs/build_async_await_commonjs.js b/test/build_async_await_commonjs/build_async_await_commonjs.js deleted file mode 100644 index b85a9c7220..0000000000 --- a/test/build_async_await_commonjs/build_async_await_commonjs.js +++ /dev/null @@ -1,4 +0,0 @@ -export const ask = async () => { - const value = await Promise.resolve(42) - return value -} diff --git a/test/build_module_force_inline_systemjs/build_module_force_inline_systemjs.html b/test/build_module_force_inline/build_module_force_inline.html similarity index 100% rename from test/build_module_force_inline_systemjs/build_module_force_inline_systemjs.html rename to test/build_module_force_inline/build_module_force_inline.html diff --git a/test/build_module_force_inline_systemjs/build_module_force_inline_systemjs.test.js b/test/build_module_force_inline/build_module_force_inline_systemjs.test.js similarity index 90% rename from test/build_module_force_inline_systemjs/build_module_force_inline_systemjs.test.js rename to test/build_module_force_inline/build_module_force_inline_systemjs.test.js index 4e6b48f698..88c59f1af6 100644 --- a/test/build_module_force_inline_systemjs/build_module_force_inline_systemjs.test.js +++ b/test/build_module_force_inline/build_module_force_inline_systemjs.test.js @@ -4,7 +4,6 @@ import { urlToRelativeUrl, readFile, resolveUrl, - urlToBasename, } from "@jsenv/filesystem" import { buildProject } from "@jsenv/core" @@ -25,14 +24,13 @@ const testDirectoryRelativeUrl = urlToRelativeUrl( testDirectoryUrl, jsenvCoreDirectoryUrl, ) -const testDirectoryname = urlToBasename(testDirectoryRelativeUrl) const jsenvDirectoryRelativeUrl = `${testDirectoryRelativeUrl}.jsenv/` const buildDirectoryRelativeUrl = `${testDirectoryRelativeUrl}dist/systemjs/` -const mainFilename = `${testDirectoryname}.html` +const mainFilename = `build_module_force_inline.html` const entryPointMap = { [`./${testDirectoryRelativeUrl}${mainFilename}`]: "./main.html", } -await buildProject({ +const { buildMappings } = await buildProject({ ...GENERATE_SYSTEMJS_BUILD_TEST_PARAMS, // logLevel: "info", jsenvDirectoryRelativeUrl, @@ -72,8 +70,8 @@ const htmlString = await readFile(htmlBuildUrl) srcAttribute: undefined, mappings: { imports: { - "./file.js": "./file-ec1c9738.js", - "./main.js": "./main-007250a8.js", + "./file.js": `./${buildMappings[`${testDirectoryRelativeUrl}file.js`]}`, + "./main.js": `./main-fddc88f1.js`, // should not here because was inlined but that's ok }, }, } diff --git a/test/build_module_force_inline_systemjs/file.js b/test/build_module_force_inline/file.js similarity index 100% rename from test/build_module_force_inline_systemjs/file.js rename to test/build_module_force_inline/file.js diff --git a/test/build_module_force_inline_systemjs/main.js b/test/build_module_force_inline/main.js similarity index 100% rename from test/build_module_force_inline_systemjs/main.js rename to test/build_module_force_inline/main.js diff --git a/test/build_module_force_inline_systemjs/project.importmap b/test/build_module_force_inline/project.importmap similarity index 100% rename from test/build_module_force_inline_systemjs/project.importmap rename to test/build_module_force_inline/project.importmap diff --git a/test/build_modulepreload/build_modulepreload.test.js b/test/build_modulepreload/build_modulepreload_esmodule.test.js similarity index 85% rename from test/build_modulepreload/build_modulepreload.test.js rename to test/build_modulepreload/build_modulepreload_esmodule.test.js index af0479af44..a8f4803340 100644 --- a/test/build_modulepreload/build_modulepreload.test.js +++ b/test/build_modulepreload/build_modulepreload_esmodule.test.js @@ -1,10 +1,5 @@ import { assert } from "@jsenv/assert" -import { - resolveUrl, - urlToRelativeUrl, - urlToBasename, - readFile, -} from "@jsenv/filesystem" +import { resolveUrl, urlToRelativeUrl, readFile } from "@jsenv/filesystem" import { buildProject } from "@jsenv/core" import { jsenvCoreDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js" @@ -19,11 +14,10 @@ const testDirectoryRelativeUrl = urlToRelativeUrl( testDirectoryUrl, jsenvCoreDirectoryUrl, ) -const testDirectoryname = urlToBasename(testDirectoryRelativeUrl) const jsenvDirectoryRelativeUrl = `${testDirectoryRelativeUrl}.jsenv/` const buildDirectoryRelativeUrl = `${testDirectoryRelativeUrl}dist/esmodule/` const entryPointMap = { - [`./${testDirectoryRelativeUrl}${testDirectoryname}.html`]: "./main.html", + [`./${testDirectoryRelativeUrl}build_modulepreload.html`]: "./main.html", } const { buildMappings } = await buildProject({ diff --git a/test/build_modulepreload/build_modulepreload_systemjs.test.js b/test/build_modulepreload/build_modulepreload_systemjs.test.js index 0ff806a747..6b3b17b44c 100644 --- a/test/build_modulepreload/build_modulepreload_systemjs.test.js +++ b/test/build_modulepreload/build_modulepreload_systemjs.test.js @@ -1,10 +1,5 @@ import { assert } from "@jsenv/assert" -import { - resolveUrl, - urlToRelativeUrl, - urlToBasename, - readFile, -} from "@jsenv/filesystem" +import { resolveUrl, urlToRelativeUrl, readFile } from "@jsenv/filesystem" import { buildProject } from "@jsenv/core" import { jsenvCoreDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js" @@ -19,13 +14,12 @@ const testDirectoryRelativeUrl = urlToRelativeUrl( testDirectoryUrl, jsenvCoreDirectoryUrl, ) -const testDirectoryname = urlToBasename(testDirectoryRelativeUrl) const jsenvDirectoryRelativeUrl = `${testDirectoryRelativeUrl}.jsenv/` const buildDirectoryRelativeUrl = `${testDirectoryRelativeUrl}dist/systemjs/` const entryPointMap = { - [`./${testDirectoryRelativeUrl}${testDirectoryname}.html`]: "./main.html", + [`./${testDirectoryRelativeUrl}build_modulepreload.html`]: "./main.html", } -await buildProject({ +const { buildMappings } = await buildProject({ ...GENERATE_ESMODULE_BUILD_TEST_PARAMS, jsenvDirectoryRelativeUrl, buildDirectoryRelativeUrl, @@ -52,7 +46,7 @@ await buildProject({ } const expected = { rel: "preload", - href: "main-2f012c65.js", + href: buildMappings[`${testDirectoryRelativeUrl}main.js`], } assert({ actual, expected }) } diff --git a/test/build_top_level_await_systemjs/build_top_level_await_systemjs.js b/test/build_top_level_await_systemjs/build_top_level_await_systemjs.js deleted file mode 100644 index cccb446fd1..0000000000 --- a/test/build_top_level_await_systemjs/build_top_level_await_systemjs.js +++ /dev/null @@ -1 +0,0 @@ -export const value = await Promise.resolve(42) diff --git a/test/build_top_level_await_systemjs/index.html b/test/build_top_level_await_systemjs/index.html deleted file mode 100644 index 99daaa9abc..0000000000 --- a/test/build_top_level_await_systemjs/index.html +++ /dev/null @@ -1,9 +0,0 @@ - -
-