diff --git a/babel.config.js b/babel.config.js index 58f0471a2..d3d5b2957 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,3 +1,4 @@ +const extensionResolver = require('./scripts/babel/extension-resolver'); const wrapWarningWithDevCheck = require('./scripts/babel/wrap-warning-with-dev-check'); module.exports = (api) => { @@ -28,6 +29,12 @@ module.exports = (api) => { ], plugins: clean([ wrapWarningWithDevCheck, + [ + extensionResolver, + { + modulesToResolve: ['@algolia/autocomplete-shared'], + }, + ], [ 'inline-replace-variables', { diff --git a/packages/autocomplete-core/package.json b/packages/autocomplete-core/package.json index 368824472..af14d8cde 100644 --- a/packages/autocomplete-core/package.json +++ b/packages/autocomplete-core/package.json @@ -16,6 +16,20 @@ "umd:main": "dist/umd/index.production.js", "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/utils": "./dist/esm/utils/index.js", + "./dist/esm/utils/*": "./dist/esm/utils/*.js", + "./dist/esm/utils/*.js": "./dist/esm/utils/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js" + }, "sideEffects": false, "files": [ "dist/" diff --git a/packages/autocomplete-js/package.json b/packages/autocomplete-js/package.json index 2f2661025..ef83c306d 100644 --- a/packages/autocomplete-js/package.json +++ b/packages/autocomplete-js/package.json @@ -17,6 +17,29 @@ "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/components": "./dist/esm/components/index.js", + "./dist/esm/components/*": "./dist/esm/components/*.js", + "./dist/esm/components/*.js": "./dist/esm/components/*.js", + "./dist/esm/elements": "./dist/esm/elements/index.js", + "./dist/esm/elements/*": "./dist/esm/elements/*.js", + "./dist/esm/elements/*.js": "./dist/esm/elements/*.js", + "./dist/esm/requesters": "./dist/esm/requesters/index.js", + "./dist/esm/requesters/*": "./dist/esm/requesters/*.js", + "./dist/esm/requesters/*.js": "./dist/esm/requesters/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js", + "./dist/esm/utils": "./dist/esm/utils/index.js", + "./dist/esm/utils/*": "./dist/esm/utils/*.js", + "./dist/esm/utils/*.js": "./dist/esm/utils/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-plugin-algolia-insights/package.json b/packages/autocomplete-plugin-algolia-insights/package.json index 3470fa29f..d5cb4b70b 100644 --- a/packages/autocomplete-plugin-algolia-insights/package.json +++ b/packages/autocomplete-plugin-algolia-insights/package.json @@ -17,6 +17,17 @@ "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-plugin-query-suggestions/package.json b/packages/autocomplete-plugin-query-suggestions/package.json index 43b9e6f5b..04e29cd2d 100644 --- a/packages/autocomplete-plugin-query-suggestions/package.json +++ b/packages/autocomplete-plugin-query-suggestions/package.json @@ -17,6 +17,17 @@ "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-plugin-recent-searches/package.json b/packages/autocomplete-plugin-recent-searches/package.json index b883bebc4..695b70868 100644 --- a/packages/autocomplete-plugin-recent-searches/package.json +++ b/packages/autocomplete-plugin-recent-searches/package.json @@ -17,6 +17,17 @@ "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-plugin-redirect-url/package.json b/packages/autocomplete-plugin-redirect-url/package.json index 4887fba6d..0493e19f1 100644 --- a/packages/autocomplete-plugin-redirect-url/package.json +++ b/packages/autocomplete-plugin-redirect-url/package.json @@ -17,6 +17,17 @@ "unpkg": "dist/umd/index.production.js", "jsdelivr": "dist/umd/index.production.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-plugin-tags/package.json b/packages/autocomplete-plugin-tags/package.json index 86ccb4568..db85a6528 100644 --- a/packages/autocomplete-plugin-tags/package.json +++ b/packages/autocomplete-plugin-tags/package.json @@ -19,6 +19,21 @@ "sideEffects": [ "*.css" ], + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js", + "./theme.css": "./dist/theme.css", + "./theme.min.css": "./dist/theme.min.css", + "./dist/theme.css": "./dist/theme.css", + "./dist/theme.min.css": "./dist/theme.min.css" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-preset-algolia/package.json b/packages/autocomplete-preset-algolia/package.json index 79df68ff0..810e3f897 100644 --- a/packages/autocomplete-preset-algolia/package.json +++ b/packages/autocomplete-preset-algolia/package.json @@ -10,6 +10,32 @@ "url": "https://www.algolia.com" }, "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/constants": "./dist/esm/constants/index.js", + "./dist/esm/constants/*": "./dist/esm/constants/*.js", + "./dist/esm/constants/*.js": "./dist/esm/constants/*.js", + "./dist/esm/highlight": "./dist/esm/highlight/index.js", + "./dist/esm/highlight/*": "./dist/esm/highlight/*.js", + "./dist/esm/highlight/*.js": "./dist/esm/highlight/*.js", + "./dist/esm/requester": "./dist/esm/requester/index.js", + "./dist/esm/requester/*": "./dist/esm/requester/*.js", + "./dist/esm/requester/*.js": "./dist/esm/requester/*.js", + "./dist/esm/search": "./dist/esm/search/index.js", + "./dist/esm/search/*": "./dist/esm/search/*.js", + "./dist/esm/search/*.js": "./dist/esm/search/*.js", + "./dist/esm/types": "./dist/esm/types/index.js", + "./dist/esm/types/*": "./dist/esm/types/*.js", + "./dist/esm/types/*.js": "./dist/esm/types/*.js", + "./dist/esm/utils": "./dist/esm/utils/index.js", + "./dist/esm/utils/*": "./dist/esm/utils/*.js", + "./dist/esm/utils/*.js": "./dist/esm/utils/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-shared/package.json b/packages/autocomplete-shared/package.json index 2e0e50a2c..c98c689b0 100644 --- a/packages/autocomplete-shared/package.json +++ b/packages/autocomplete-shared/package.json @@ -14,6 +14,23 @@ "module": "dist/esm/index.js", "main": "dist/esm/index.js", "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/esm/index.js", + "./package.json": "./package.json", + "./dist/esm": "./dist/esm/index.js", + "./dist/esm/*": "./dist/esm/*.js", + "./dist/esm/*.js": "./dist/esm/*.js", + "./dist/esm/core": "./dist/esm/core/index.js", + "./dist/esm/core/*": "./dist/esm/core/*.js", + "./dist/esm/core/*.js": "./dist/esm/core/*.js", + "./dist/esm/js": "./dist/esm/js/index.js", + "./dist/esm/js/*": "./dist/esm/js/*.js", + "./dist/esm/js/*.js": "./dist/esm/js/*.js", + "./dist/esm/preset-algolia": "./dist/esm/preset-algolia/index.js", + "./dist/esm/preset-algolia/*": "./dist/esm/preset-algolia/*.js", + "./dist/esm/preset-algolia/*.js": "./dist/esm/preset-algolia/*.js" + }, "files": [ "dist/" ], diff --git a/packages/autocomplete-theme-classic/package.json b/packages/autocomplete-theme-classic/package.json index e420bcb42..2e92507ba 100644 --- a/packages/autocomplete-theme-classic/package.json +++ b/packages/autocomplete-theme-classic/package.json @@ -12,6 +12,15 @@ "sideEffects": [ "*.css" ], + "type": "module", + "exports": { + ".": "./dist/theme.min.css", + "./package.json": "./package.json", + "./theme.css": "./dist/theme.min.css", + "./theme.min.css": "./dist/theme.min.css", + "./dist/theme.css": "./dist/theme.min.css", + "./dist/theme.min.css": "./dist/theme.min.css" + }, "files": [ "dist/" ], diff --git a/scripts/babel/extension-resolver.js b/scripts/babel/extension-resolver.js new file mode 100644 index 000000000..1c6b8d4cf --- /dev/null +++ b/scripts/babel/extension-resolver.js @@ -0,0 +1,198 @@ +// original source: https://github.com/shimataro/babel-plugin-module-extension-resolver +// To create proper ES Modules, the paths imported need to be fully-specified, +// and can't be resolved like is possible with CommonJS. To have large compatibility +// without much hassle, we don't use extensions *inside* the source code, but add +// them with this plugin. + +const fs = require('fs'); +const path = require('path'); + +const PLUGIN_NAME = 'babel-plugin-extension-resolver'; + +module.exports = function extensionResolver( + { types }, + { + modulesToResolve = [], + srcExtensions = ['.js', '.ts', '.tsx'], + dstExtension = '.js', + } +) { + return { + name: PLUGIN_NAME, + visitor: { + Program: { + enter: (programPath, state) => { + const fileName = state.filename; + programPath.traverse( + { + ImportDeclaration(declaration) { + const source = declaration.get('source'); + replaceSource({ + types, + source, + fileName, + modulesToResolve, + srcExtensions, + dstExtension, + }); + }, + ExportDeclaration(declaration) { + const source = declaration.get('source'); + if (Array.isArray(source)) { + return; + } + replaceSource({ + types, + source, + fileName, + modulesToResolve, + srcExtensions, + dstExtension, + }); + }, + }, + state + ); + }, + }, + }, + }; +}; + +function replaceSource({ + types, + source, + fileName, + modulesToResolve, + srcExtensions, + dstExtension, +}) { + if (!source.isStringLiteral()) { + return; + } + const sourcePath = source.node.value; + if ( + modulesToResolve.every((prefix) => !sourcePath.startsWith(`${prefix}/`)) && + !isRelativeDependency(sourcePath) + ) { + return; + } + const baseDir = path.dirname(fileName); + + let normalizedPath; + if (isRelativeDependency(sourcePath)) { + const resolvedPath = resolveRelativePath( + baseDir, + sourcePath, + srcExtensions, + dstExtension + ); + normalizedPath = normalizeRelativePath(resolvedPath); + } else { + const resolvedPath = resolveAbsolutePath(sourcePath); + normalizedPath = normalizeAbsolutePath(resolvedPath); + } + + source.replaceWith(types.stringLiteral(normalizedPath)); +} + +function resolveRelativePath(baseDir, sourcePath, srcExtensions, dstExtension) { + let resolvedPath = resolveRelativeExtension( + baseDir, + sourcePath, + srcExtensions, + dstExtension + ); + + if (resolvedPath === null) { + resolvedPath = resolveRelativeExtension( + baseDir, + path.join(sourcePath, 'index'), + srcExtensions, + dstExtension + ); + } + + if (resolvedPath === null) { + throw new Error(`import for "${sourcePath}" could not be resolved`); + } + + return resolvedPath; +} + +/** + * @param {string} sourcePath the path to resolve using require.resolve + * @returns {string} the resolved path + */ +function resolveAbsolutePath(sourcePath) { + // The source path is composed of: 1. the package name, 2. the path inside the package. + const packageNameRegex = sourcePath.startsWith('@') + ? /^(?@[^/]+\/[^/]+)\/(?.+)/ + : /^(?[^/]+)\/(?.+)/; + const { packageName } = sourcePath.match(packageNameRegex).groups; + + // the require.resolve will return the full path of the requested file. + const fullPath = require.resolve(sourcePath); + + // the bare package could resolve to a nested file, but /package.json is always at the root. + // this gives us the path to the root of the package. + const packageJson = '/package.json'; + const packagePath = require + .resolve(packageName + packageJson) + .slice(0, -packageJson.length); + + // We overlap the two parts to get path inside the package. + const [, resolvedPath] = fullPath.split(packagePath); + + // That's then combined with the package name. + return packageName + resolvedPath; +} + +function resolveRelativeExtension( + baseDir, + sourcePath, + srcExtensions, + dstExtension +) { + const absolutePath = path.join(baseDir, sourcePath); + if (isFile(absolutePath)) { + return sourcePath; + } + for (const extension of srcExtensions) { + if (isFile(`${absolutePath}${extension}`)) { + return path.relative(baseDir, `${absolutePath}${dstExtension}`); + } + } + return null; +} + +function normalizeRelativePath(originalPath) { + let normalizedPath = originalPath; + if (path.sep === '\\') { + normalizedPath = normalizedPath.split(path.sep).join('/'); + } + if (normalizedPath[0] !== '.') { + normalizedPath = `./${normalizedPath}`; + } + return normalizedPath; +} + +function normalizeAbsolutePath(originalPath) { + let normalizedPath = originalPath; + if (path.sep === '\\') { + normalizedPath = normalizedPath.split(path.sep).join('/'); + } + return normalizedPath; +} + +function isFile(pathName) { + try { + return fs.statSync(pathName).isFile(); + } catch (err) { + return false; + } +} + +function isRelativeDependency(sourcePath) { + return sourcePath[0] === '.'; +}