diff --git a/changelogs/fragments/9205.yml b/changelogs/fragments/9205.yml new file mode 100644 index 000000000000..a3870d226fc6 --- /dev/null +++ b/changelogs/fragments/9205.yml @@ -0,0 +1,2 @@ +infra: +- Add path alias support for webpack and babel ([#9205](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9205)) \ No newline at end of file diff --git a/packages/osd-babel-preset/node_preset.js b/packages/osd-babel-preset/node_preset.js index 43915e239c38..2925c1b76826 100644 --- a/packages/osd-babel-preset/node_preset.js +++ b/packages/osd-babel-preset/node_preset.js @@ -28,6 +28,8 @@ * under the License. */ +const path = require('path'); + module.exports = (_, options = {}) => { return { presets: [ @@ -60,5 +62,17 @@ module.exports = (_, options = {}) => { ], require('./common_preset'), ], + plugins: [ + [ + require.resolve('babel-plugin-module-resolver'), + { + root: [path.resolve(__dirname, '../..')], + alias: { + 'opensearch-dashboards/server': './src/core/server', + 'opensearch-dashboards/public': './src/core/public', + }, + }, + ], + ], }; }; diff --git a/packages/osd-babel-preset/package.json b/packages/osd-babel-preset/package.json index 676afffe7cdc..919b865fa0f3 100644 --- a/packages/osd-babel-preset/package.json +++ b/packages/osd-babel-preset/package.json @@ -15,6 +15,7 @@ "@babel/preset-react": "^7.22.9", "@babel/preset-typescript": "^7.22.9", "babel-plugin-add-module-exports": "^1.0.4", + "babel-plugin-module-resolver": "^5.0.1", "babel-plugin-styled-components": "^2.0.2", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "browserslist": "^4.21.10", diff --git a/packages/osd-optimizer/src/worker/bundle_refs_plugin.ts b/packages/osd-optimizer/src/worker/bundle_refs_plugin.ts index 1eb2cd55eeb5..88431d405925 100644 --- a/packages/osd-optimizer/src/worker/bundle_refs_plugin.ts +++ b/packages/osd-optimizer/src/worker/bundle_refs_plugin.ts @@ -20,7 +20,6 @@ */ import Path from 'path'; -import Fs from 'fs'; import webpack from 'webpack'; @@ -29,20 +28,6 @@ import { BundleRefModule } from './bundle_ref_module'; const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx']; -function safeStat(path: string): Promise { - return new Promise((resolve, reject) => { - Fs.stat(path, (error, stat) => { - if (error?.code === 'ENOENT') { - resolve(undefined); - } else if (error) { - reject(error); - } else { - resolve(stat); - } - }); - }); -} - interface RequestData { context: string; dependencies: Array<{ request: string }>; @@ -80,7 +65,7 @@ export class BundleRefsPlugin { const context = data.context; const dep = data.dependencies[0]; - this.maybeReplaceImport(context, dep.request).then( + this.maybeReplaceImport(context, dep.request, compiler).then( (module) => { if (!module) { wrappedFactory(data, callback); @@ -134,64 +119,16 @@ export class BundleRefsPlugin { }); } - private cachedResolveRefEntry(ref: BundleRef) { - const cached = this.resolvedRefEntryCache.get(ref); - - if (cached) { - return cached; - } - - const absoluteRequest = Path.resolve(ref.contextDir, ref.entry); - const promise = this.cachedResolveRequest(absoluteRequest).then((resolved) => { - if (!resolved) { - throw new Error(`Unable to resolve request [${ref.entry}] relative to [${ref.contextDir}]`); - } - - return resolved; - }); - this.resolvedRefEntryCache.set(ref, promise); - return promise; - } - - private cachedResolveRequest(absoluteRequest: string) { - const cached = this.resolvedRequestCache.get(absoluteRequest); - - if (cached) { - return cached; - } - - const promise = this.resolveRequest(absoluteRequest); - this.resolvedRequestCache.set(absoluteRequest, promise); - return promise; - } - - private async resolveRequest(absoluteRequest: string) { - const stats = await safeStat(absoluteRequest); - if (stats && stats.isFile()) { - return absoluteRequest; - } - - // look for an index file in directories - if (stats?.isDirectory()) { - for (const ext of RESOLVE_EXTENSIONS) { - const indexPath = Path.resolve(absoluteRequest, `index${ext}`); - const indexStats = await safeStat(indexPath); - if (indexStats?.isFile()) { - return indexPath; + private async resolve(request: string, context: string, compiler: webpack.Compiler) { + const resolver = compiler.resolverFactory.get('normal'); + return new Promise((resolve) => { + resolver.resolve({}, context, request, {}, (err: Error, resolvedPath: string) => { + if (err) { + resolve(undefined); } - } - } - - // look for a file with one of the supported extensions - for (const ext of RESOLVE_EXTENSIONS) { - const filePath = `${absoluteRequest}${ext}`; - const fileStats = await safeStat(filePath); - if (fileStats?.isFile()) { - return filePath; - } - } - - return; + resolve(resolvedPath); + }); + }); } /** @@ -200,9 +137,12 @@ export class BundleRefsPlugin { * then an error is thrown. If the request does not resolve to a bundleRef then * undefined is returned. Otherwise it returns the referenced bundleRef. */ - private async maybeReplaceImport(context: string, request: string) { - // ignore imports that have loaders defined or are not relative seeming - if (request.includes('!') || !request.startsWith('.')) { + private async maybeReplaceImport(context: string, request: string, compiler: webpack.Compiler) { + const alias = Object.keys(compiler.options.resolve?.alias ?? {}); + const isAliasRequest = alias.some((a) => request.startsWith(a)); + + // For non-alias import path, ignore imports that have loaders defined or are not relative seeming + if (!isAliasRequest && (request.includes('!') || !request.startsWith('.'))) { return; } @@ -211,13 +151,12 @@ export class BundleRefsPlugin { return; } - const absoluteRequest = Path.resolve(context, request); - if (absoluteRequest.startsWith(this.ignorePrefix)) { + const resolved = await this.resolve(request, context, compiler); + if (!resolved) { return; } - const resolved = await this.cachedResolveRequest(absoluteRequest); - if (!resolved) { + if (resolved.startsWith(this.ignorePrefix)) { return; } @@ -228,7 +167,7 @@ export class BundleRefsPlugin { } for (const ref of possibleRefs) { - const resolvedEntry = await this.cachedResolveRefEntry(ref); + const resolvedEntry = await this.resolve(`./${ref.entry}`, ref.contextDir, compiler); if (resolved !== resolvedEntry) { continue; } diff --git a/packages/osd-optimizer/src/worker/webpack.config.ts b/packages/osd-optimizer/src/worker/webpack.config.ts index 1917b145a712..e78b0395b5aa 100644 --- a/packages/osd-optimizer/src/worker/webpack.config.ts +++ b/packages/osd-optimizer/src/worker/webpack.config.ts @@ -274,6 +274,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: mainFields: ['browser', 'main'], alias: { core_app_image_assets: Path.resolve(worker.repoRoot, 'src/core/public/core_app/images'), + 'opensearch-dashboards/public': Path.resolve(worker.repoRoot, 'src/core/public'), }, }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 981ed82dd77a..2c1b958afaa2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -5,11 +5,11 @@ // Allows for importing from `opensearch-dashboards` package for the exported types. "opensearch-dashboards": ["./opensearch_dashboards"], "opensearch-dashboards/public": ["src/core/public"], + "opensearch-dashboards/public/*": ["src/core/public/*"], "opensearch-dashboards/server": ["src/core/server"], + "opensearch-dashboards/server/*": ["src/core/server/*"], "plugins/*": ["src/legacy/core_plugins/*/public/"], - "test_utils/*": [ - "src/test_utils/public/*" - ], + "test_utils/*": ["src/test_utils/public/*"], "fixtures/*": ["src/fixtures/*"], "@opensearch-project/opensearch": ["node_modules/@opensearch-project/opensearch/api/new"] }, diff --git a/yarn.lock b/yarn.lock index c23bc4de01dd..7db22ff1418a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5026,6 +5026,17 @@ babel-plugin-jest-hoist@^27.5.1: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-module-resolver@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz#cdeac5d4aaa3b08dd1ac23ddbf516660ed2d293e" + integrity sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg== + dependencies: + find-babel-config "^2.1.1" + glob "^9.3.3" + pkg-up "^3.1.0" + reselect "^4.1.7" + resolve "^1.22.8" + babel-plugin-polyfill-corejs2@^0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313" @@ -8625,6 +8636,13 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= +find-babel-config@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-2.1.2.tgz#2841b1bfbbbcdb971e1e39df8cbc43dafa901716" + integrity sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg== + dependencies: + json5 "^2.2.3" + find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" @@ -9180,6 +9198,16 @@ glob@^8.1.0: minimatch "^5.0.1" once "^1.3.0" +glob@^9.3.3: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + glob@~5.0.0: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -9634,6 +9662,13 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hast-to-hyperscript@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" @@ -10329,6 +10364,13 @@ is-core-module@^2.1.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-m dependencies: hasown "^2.0.0" +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -12479,6 +12521,13 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimatch@^9.0.4: version "9.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" @@ -12540,6 +12589,11 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + minipass@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" @@ -13628,7 +13682,7 @@ path-root@^0.1.1: dependencies: path-root-regex "^0.1.0" -path-scurry@^1.11.1: +path-scurry@^1.11.1, path-scurry@^1.6.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== @@ -15013,6 +15067,11 @@ reselect@^4.0.0, reselect@^4.1.5: resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.6.tgz#19ca2d3d0b35373a74dc1c98692cdaffb6602656" integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ== +reselect@^4.1.7: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== + resize-observer-polyfill@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/@4lolo/resize-observer-polyfill/-/resize-observer-polyfill-1.5.2.tgz#58868fc7224506236b5550d0c68357f0a874b84b" @@ -15086,6 +15145,15 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12. path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.8: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.3: version "2.0.0-next.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46"