diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index db3cb003a..9d5270369 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -13,6 +13,7 @@ import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import TerserPlugin from 'terser-webpack-plugin'; import { getProjectFilePath, getProjectTSConfigPath } from '../helpers/project'; +import { RuntimePackageJSONPlugin } from '../plugins/RuntimePackageJSONPlugin'; import { getDependencyVersion, hasDependency } from '../helpers/dependencies'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { applyFileReplacements } from '../helpers/fileReplacements'; @@ -20,7 +21,7 @@ import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; -import { getValue } from '../helpers/config'; +import { getValue, getValueFallbacks } from '../helpers/config'; import { getIPS } from '../helpers/host'; import { getAvailablePlatforms, @@ -46,7 +47,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // package.json is generated by the CLI with runtime options // this ensures it's not included in the bundle, but rather // resolved at runtime - config.externals(['package.json', '~/package.json']); + // config.externals(['package.json', '~/package.json']); // disable marking built-in node modules as external // since they are not available at runtime and @@ -87,7 +88,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const sourceMapAbsolutePath = getProjectFilePath( `./${ env.buildPath ?? 'platforms' - }/${platform}-sourceMaps/[file].map[query]`, + }/${platform}-sourceMaps/[file].map[query]` ); const sourceMapRelativePath = relative(outputPath, sourceMapAbsolutePath); config.output.sourceMapFilename(sourceMapRelativePath); @@ -273,7 +274,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const configFile = tsConfigPath ? { configFile: tsConfigPath, - } + } : undefined; // set up ts support @@ -353,7 +354,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const extPath = resolve(baseDir, platformRequest); try { - return require.resolve(platformRequest, { + return (require as NodeRequire).resolve(platformRequest, { paths: [baseDir], }); } catch {} @@ -452,7 +453,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * +-----------------------------------------------------------------------------------------+ */ /System.import\(\) is deprecated/, - ]), + ]) ); // todo: refine defaults @@ -494,6 +495,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { applyCopyRules(config); + // Emit a package.json file to be used at runtime containing the runtime options for the app + config.plugin('RuntimePackageJSONPlugin').use(RuntimePackageJSONPlugin, [ + { + ...getValue>('.', {}), + ...getValue>(platform, {}), + }, + ]); + config.plugin('WatchStatePlugin').use(WatchStatePlugin); config.when(env.hmr, (config) => { diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index 9c9281683..f386ac049 100644 --- a/packages/webpack5/src/helpers/config.ts +++ b/packages/webpack5/src/helpers/config.ts @@ -1,6 +1,11 @@ import { warnOnce } from './log'; import { env } from '../index'; +interface IPartialProjectConfigService { + readConfig(projectDir?: string): Record; + getValue(key: string, defaultValue?: any): T; +} + function getCLILib() { if (!env.nativescriptLibPath) { if (typeof env.nativescriptLibPath !== 'boolean') { @@ -34,9 +39,35 @@ export function getValue(key: string, defaultValue?: any): T { return defaultValue; } - return ( - lib.projectConfigService as { - getValue(key: string, defaultValue?: any): T; - } - ).getValue(key, defaultValue); + if (key === '.') { + return ( + lib.projectConfigService as IPartialProjectConfigService + ).readConfig() as T; + } + + return (lib.projectConfigService as IPartialProjectConfigService).getValue( + key, + defaultValue + ); +} + +/** + * Utility to get a value from multiple keys in the nativescript.config.ts file, until one is found, or return a default value. + * + * @param keys a list of keys to try to get the value from + * @param defaultValue The fallback value if none of the keys are set in the config. + * @returns + */ +export function getValueFallbacks( + keys: string[], + defaultValue?: any +): T { + for (const key of keys) { + const value = getValue(key); + if (value) { + return value; + } + } + + return defaultValue; } diff --git a/packages/webpack5/src/plugins/RuntimePackageJSONPlugin.ts b/packages/webpack5/src/plugins/RuntimePackageJSONPlugin.ts new file mode 100644 index 000000000..cad75896d --- /dev/null +++ b/packages/webpack5/src/plugins/RuntimePackageJSONPlugin.ts @@ -0,0 +1,30 @@ +import webpack from 'webpack'; + +const id = 'RuntimePackageJSONPlugin'; + +/** + * The platform suffix plugin will try to resolve files with a platform specifier (suffix) + * falling back to the non-platform-specific version. + * + * For example: + * import something from './something.js' + * + * will first look for './something..js' + * and if not found look for './something.js' + * + */ +export class RuntimePackageJSONPlugin { + constructor(private additionalContents: Record) {} + + apply(compiler: webpack.Compiler) { + compiler.hooks.compilation.tap(id, (compilation) => { + compilation.assets['package.json'] = new webpack.sources.RawSource( + JSON.stringify( + Object.assign({}, this.additionalContents, { main: 'bundle' }), + null, + 2 + ) + ); + }); + } +}