diff --git a/README.md b/README.md
index efe5bef..7018294 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ compiled remote types from other federated microapps into _src/@types/remotes_ f
Global type definitions from _src/@types/*.d.ts_ are included in compilation.
+Paths can be customized to meet your environment.
+
## Feature comparison tables
| Feature | @touk/
federated-types | ruanyl/dts-loader | ruanyl/webpack-remote-types-plugin | @module-federation/typescript | @cloudbeds/wmf-types-plugin |
@@ -69,6 +71,13 @@ Or it can be added to `package.json`:
}
```
+### CLI options
+
+| Option | Default value | Description |
+|-------------------------------|---------------|--------------------------------------------------------------------------------|
+| `--output-types-folder`, `-o` | `dist/@types` | Path to the output folder, absolute or relative to the working directory |
+| `--global-types`, `-g` | `src/@types` | Path to project's global ambient type definitions, relative to the working dir |
+
## Plugin Configuration
### Exposed modules
@@ -136,14 +145,16 @@ To enable verbose logging add folowing in webpack config:
### Plugin Options
-| Option | Value | Default | Description |
-|-----------------------------------------:|:--------------------:|:-------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `disableTypeCompilation` | `boolean` | `false` | Disable compilation of types |
-| `disableDownladingRemoteTypes` | `boolean` | `false` | Disable downloading of remote types |
-| `cloudbedsRemoteManifestsBaseUrl` | `string` | `'/remotes/dev-ga'` | Base URL for remote manifest files (a.k.a remote entry configs) that is specific to Cloudbeds microapps
_ Examples:_
`http://localhost:4480/remotes/dev`
`https://cb-front.cloudbeds-dev.com/remotes/[env]`
`use-domain-name` |
-| `doNotUseCloudbedsRemoteManifests` | `boolean` | `false` | Disable downloading default remote manifest files for Cloudbeds microapps (`mfd-common-remote-entry.json` and `mfd-remote-entries.json` files) and download only those provided via `remoteManifestUrls` |
-| `downloadTypesWhenIdleIntervalInSeconds` | `number`, `-1` | `60` | Synchronize types continusouly - compile types after every compilation, download when idle with a specified delay value in seconds.
`-1` - disables continuous synchronization (compile and download will happen only on startup). |
-| `remoteManifestUrls` | `RemoteManifestUrls` | `{}` | URLs to remote manifest files. A manifest contains a URL to a remote entry that is substituted in runtime. Multiple remote entries is supported via `registry` field.
More details available in [this section](#templated-remote-urls) |
+| Setting | Value | Default | Description |
+|-----------------------------------------:|:--------------------:|:--------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `dirEmittedTypes` | `string` | `@types` | Path to the output folder for emitted types, relative to the distribution folder |
+| `dirGlobalTypes` | `string` | `src/@types` | Path to project's global ambient type definitions, relative to the working dir |
+| `dirDownloadedTypes` | `string` | `src/@types/remotes` | Path to the output folder for downloaded types |
+| `disableTypeCompilation` | `boolean` | `false` | Disable compilation of types |
+| `disableDownladingRemoteTypes` | `boolean` | `false` | Disable downloading of remote types |
+| `downloadTypesWhenIdleIntervalInSeconds` | `number`, `-1` | `60` | Synchronize types continusouly - compile types after every compilation, download when idle with a specified delay value in seconds.
`-1` - disables continuous synchronization (compile and download will happen only on startup). |
+| `remoteManifestUrls` | `RemoteManifestUrls` | `{}` | URLs to remote manifest files. A manifest contains a URL to a remote entry that is substituted in runtime. Multiple remote entries is supported via `registry` field.
More details available in [this section](#templated-remote-urls) |
+| `cloudbedsRemoteManifestsBaseUrl` | `string` | `'/remotes/dev-ga'` | Base URL for remote manifest files (a.k.a remote entry configs) that is specific to Cloudbeds microapps
_ Examples:_
`http://localhost:4480/remotes/dev`
`https://cb-front.cloudbeds-dev.com/remotes/[env]`
`use-domain-name`.
Following remote manifest files are downloaded: `mfd-common-remote-entry.json` and `mfd-remote-entries.json` files).
`remoteManifestUrls` is ignored when this setting has a value other than `undefined`. |
## Consuming remote types
diff --git a/package-lock.json b/package-lock.json
index 27da9a8..fd868d5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"license": "UNLICENSED",
"dependencies": {
"download": "^8.0.0",
+ "minimist": "^1.2.6",
"mkdirp": "^1.0.4"
},
"bin": {
@@ -18,6 +19,7 @@
"devDependencies": {
"@types/download": "^8.0.1",
"@types/jest": "^28.1.6",
+ "@types/minimist": "^1.2.2",
"@types/mkdirp": "^1.0.2",
"jest": "^28.1.3",
"ts-jest": "^28.0.7",
@@ -1203,6 +1205,12 @@
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"peer": true
},
+ "node_modules/@types/minimist": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "dev": true
+ },
"node_modules/@types/mkdirp": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.2.tgz",
@@ -3936,6 +3944,11 @@
"node": "*"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+ },
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -6373,6 +6386,12 @@
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"peer": true
},
+ "@types/minimist": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "dev": true
+ },
"@types/mkdirp": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.2.tgz",
@@ -8495,6 +8514,11 @@
"brace-expansion": "^1.1.7"
}
},
+ "minimist": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+ },
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
diff --git a/package.json b/package.json
index 133794a..7316e2b 100644
--- a/package.json
+++ b/package.json
@@ -21,11 +21,13 @@
},
"dependencies": {
"download": "^8.0.0",
+ "minimist": "^1.2.6",
"mkdirp": "^1.0.4"
},
"devDependencies": {
"@types/download": "^8.0.1",
"@types/jest": "^28.1.6",
+ "@types/minimist": "^1.2.2",
"@types/mkdirp": "^1.0.2",
"jest": "^28.1.3",
"ts-jest": "^28.0.7",
diff --git a/src/constants.ts b/src/constants.ts
index b29797c..b9b761a 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -1,10 +1,10 @@
export const FEDERATION_CONFIG_FILE = 'federation.config.json';
-export const DIR_DIST = 'dist';
-export const DIR_EMITTED_TYPES = '@types';
+export const DEFAULT_DIR_DIST = 'dist';
+export const DEFAULT_DIR_EMITTED_TYPES = '@types';
-export const DIR_SRC_TYPES = 'src/@types';
-export const DIR_DOWNLOADED_TYPES = `${DIR_SRC_TYPES}/remotes`;
+export const DEFAULT_DIR_GLOBAL_TYPES = 'src/@types';
+export const DEFAULT_DIR_DOWNLOADED_TYPES = `src/@types/remotes`;
export const DEFAULT_DOWNLOAD_TYPES_INTERVAL_IN_SECONDS = 60;
diff --git a/src/helpers/cloudbedsRemoteManifests.ts b/src/helpers/cloudbedsRemoteManifests.ts
index 6777240..e612c65 100644
--- a/src/helpers/cloudbedsRemoteManifests.ts
+++ b/src/helpers/cloudbedsRemoteManifests.ts
@@ -7,7 +7,7 @@ import {
import { ModuleFederationTypesPluginOptions, RemoteManifestUrls } from '../types';
export function getRemoteManifestUrls(options?: ModuleFederationTypesPluginOptions): RemoteManifestUrls | undefined {
- if (!options?.doNotUseCloudbedsRemoteManifests) {
+ if (options?.cloudbedsRemoteManifestsBaseUrl !== undefined) {
let baseUrl = options?.cloudbedsRemoteManifestsBaseUrl;
if (!baseUrl || baseUrl === 'use-domain-name') {
baseUrl = `${CLOUDBEDS_DEV_FRONTEND_ASSETS_DOMAIN}/remotes/dev-ga`;
diff --git a/src/helpers/compileTypes.ts b/src/helpers/compileTypes.ts
index f3adbf7..a13b5f7 100644
--- a/src/helpers/compileTypes.ts
+++ b/src/helpers/compileTypes.ts
@@ -5,7 +5,6 @@ import ts from 'typescript';
import { getLogger } from './logger';
-import { DIR_SRC_TYPES } from '../constants';
import { CompileTypesResult, FederationConfig } from '../types';
import { getAllFilePaths } from './files';
@@ -27,7 +26,7 @@ export function reportCompileDiagnostic(diagnostic: ts.Diagnostic): void {
logger.log(' at', `${diagnostic.file!.fileName}:${line + 1}`, '\n');
}
-export function compileTypes(exposedComponents: string[], outFile: string): CompileTypesResult {
+export function compileTypes(exposedComponents: string[], outFile: string, dirGlobalTypes: string): CompileTypesResult {
const logger = getLogger();
const exposedFileNames = Object.values(exposedComponents);
@@ -44,8 +43,8 @@ export function compileTypes(exposedComponents: string[], outFile: string): Comp
host.writeFile = (_fileName: string, contents: string) => fileContent = contents;
// Including global type definitions from `src/@types` directory
- if (fs.existsSync(DIR_SRC_TYPES)) {
- exposedFileNames.push(...getAllFilePaths(`./${DIR_SRC_TYPES}`).filter(path => path.endsWith('.d.ts')));
+ if (fs.existsSync(dirGlobalTypes)) {
+ exposedFileNames.push(...getAllFilePaths(`./${dirGlobalTypes}`).filter(path => path.endsWith('.d.ts')));
}
logger.log('Including a set of root files in compilation', exposedFileNames);
diff --git a/src/helpers/downloadTypes.ts b/src/helpers/downloadTypes.ts
index b0feafb..a38af7e 100644
--- a/src/helpers/downloadTypes.ts
+++ b/src/helpers/downloadTypes.ts
@@ -3,7 +3,6 @@ import fs from 'fs';
import mkdirp from 'mkdirp';
import path from 'path';
-import { DIR_DOWNLOADED_TYPES, DIR_EMITTED_TYPES } from '../constants';
import { RemoteManifest, RemoteManifestUrls, RemotesRegistryManifest } from '../types';
import { getLogger } from './logger';
@@ -15,10 +14,10 @@ async function downloadRemoteEntryManifest(url: string): Promise {
return JSON.parse(json);
}
-async function downloadRemoteEntryTypes(remoteName: string, dtsUrl: string): Promise {
+async function downloadRemoteEntryTypes(remoteName: string, dtsUrl: string, dirDownloadedTypes: string): Promise {
const logger = getLogger();
const types = (await download(dtsUrl, downloadOptions)).toString();
- const outDir = path.join(DIR_DOWNLOADED_TYPES, remoteName);
+ const outDir = path.join(dirDownloadedTypes, remoteName);
const outFile = path.join(outDir, 'index.d.ts');
let shouldWriteFile = true;
@@ -71,6 +70,8 @@ export async function downloadRemoteEntryURLsFromManifests(remoteManifestUrls?:
}
export async function downloadTypes(
+ dirEmittedTypes: string,
+ dirDownloadedTypes: string,
remotes: Record,
remoteManifestUrls?: RemoteManifestUrls,
): Promise {
@@ -91,8 +92,13 @@ export async function downloadTypes(
try {
const remoteEntryUrl = remoteEntryURLs[remoteName] || remoteLocation.split('@')[1];
const remoteEntryBaseUrl = remoteEntryUrl.split('/').slice(0, -1).join('/');
+ const promiseDownload = downloadRemoteEntryTypes(
+ remoteName,
+ `${remoteEntryBaseUrl}/${dirEmittedTypes}/index.d.ts`,
+ dirDownloadedTypes,
+ )
- promises.push(downloadRemoteEntryTypes(remoteName, `${remoteEntryBaseUrl}/${DIR_EMITTED_TYPES}/index.d.ts`));
+ promises.push(promiseDownload);
} catch (err) {
logger.error(`${remoteName}: '${remoteLocation}' is not a valid remote federated module URL`);
logger.log(err);
diff --git a/src/make-federated-types.ts b/src/make-federated-types.ts
index 1302be1..a2ecf03 100644
--- a/src/make-federated-types.ts
+++ b/src/make-federated-types.ts
@@ -1,21 +1,31 @@
#!/usr/bin/env node
+import parseArgs from 'minimist';
import path from 'path';
-import { DIR_DIST, DIR_EMITTED_TYPES } from './constants';
+import { DEFAULT_DIR_DIST, DEFAULT_DIR_EMITTED_TYPES, DEFAULT_DIR_GLOBAL_TYPES } from './constants';
import { compileTypes, rewritePathsWithExposedFederatedModules } from './helpers/compileTypes';
import { assertRunningFromRoot, getFederationConfig } from './helpers/cli';
assertRunningFromRoot();
+const argv = parseArgs(process.argv.slice(2), {
+ alias: {
+ 'global-types': 'g',
+ 'output-types-folder': 'o',
+ },
+});
+
const federationConfig = getFederationConfig();
const compileFiles = Object.values(federationConfig.exposes);
-const outFile = path.join(DIR_DIST, DIR_EMITTED_TYPES, 'index.d.ts');
+const outDir = argv['output-types-folder'] || path.join(DEFAULT_DIR_DIST, DEFAULT_DIR_EMITTED_TYPES);
+const outFile = path.join(outDir, 'index.d.ts');
+const dirGlobalTypes = argv['global-types'] || DEFAULT_DIR_GLOBAL_TYPES;
console.log(`Emitting types for ${compileFiles.length} exposed module(s)`);
-const { isSuccess, typeDefinitions } = compileTypes(compileFiles as string[], outFile);
+const { isSuccess, typeDefinitions } = compileTypes(compileFiles as string[], outFile, dirGlobalTypes);
if (!isSuccess) {
process.exit(1);
}
diff --git a/src/plugin.spec.ts b/src/plugin.spec.ts
index d5764f7..d4feea7 100644
--- a/src/plugin.spec.ts
+++ b/src/plugin.spec.ts
@@ -3,7 +3,7 @@ import webpack, { Compilation, Compiler } from 'webpack';
import { downloadTypes } from './helpers/downloadTypes';
import { ModuleFederationTypesPlugin } from './plugin';
import { ModuleFederationPluginOptions, ModuleFederationTypesPluginOptions } from './types';
-import { CloudbedsMicrofrontend } from './constants';
+import { CloudbedsMicrofrontend, DEFAULT_DIR_DOWNLOADED_TYPES, DEFAULT_DIR_EMITTED_TYPES } from './constants';
jest.mock('./helpers/downloadTypes');
@@ -64,6 +64,8 @@ describe('ModuleFederationTypesPlugin', () => {
installPlugin(moduleFederationPluginOptions, typesPluginOptions);
expect(mockDownloadTypes.mock.calls[0]).toEqual([
+ DEFAULT_DIR_EMITTED_TYPES,
+ DEFAULT_DIR_DOWNLOADED_TYPES,
moduleFederationPluginOptions.remotes,
typesPluginOptions.remoteManifestUrls,
]);
diff --git a/src/plugin.ts b/src/plugin.ts
index 2316b0a..bba2042 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -3,9 +3,11 @@ import { Compiler, WebpackPluginInstance } from 'webpack';
import {
CLOUDBEDS_DEPLOYMENT_ENV_WITH_DISABLED_REMOTE_TYPES_DOWNLOAD,
+ DEFAULT_DIR_DIST,
+ DEFAULT_DIR_DOWNLOADED_TYPES,
+ DEFAULT_DIR_EMITTED_TYPES,
+ DEFAULT_DIR_GLOBAL_TYPES,
DEFAULT_DOWNLOAD_TYPES_INTERVAL_IN_SECONDS,
- DIR_DIST,
- DIR_EMITTED_TYPES
} from './constants';
import { getRemoteManifestUrls } from './helpers/cloudbedsRemoteManifests';
import { compileTypes, rewritePathsWithExposedFederatedModules } from './helpers/compileTypes';
@@ -55,12 +57,18 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance {
// Define path for the emitted typings file
const { exposes, remotes } = federationPluginOptions;
- const distPath = compiler.options.devServer?.static?.directory || compiler.options.output?.path || DIR_DIST;
- const outFile = path.join(distPath, DIR_EMITTED_TYPES, 'index.d.ts');
+
+ const dirDist = compiler.options.devServer?.static?.directory
+ || compiler.options.output?.path
+ || DEFAULT_DIR_DIST;
+ const dirEmittedTypes = this.options?.dirEmittedTypes || DEFAULT_DIR_EMITTED_TYPES;
+ const dirGlobalTypes = this.options?.dirGlobalTypes || DEFAULT_DIR_GLOBAL_TYPES;
+ const dirDownloadedTypes = this.options?.dirDownloadedTypes || DEFAULT_DIR_DOWNLOADED_TYPES;
+ const outFile = path.join(dirDist, dirEmittedTypes, 'index.d.ts');
// Create types for exposed modules
const compileTypesHook = () => {
- const { isSuccess, typeDefinitions } = compileTypes(exposes as string[], outFile);
+ const { isSuccess, typeDefinitions } = compileTypes(exposes as string[], outFile, dirGlobalTypes);
if (isSuccess) {
rewritePathsWithExposedFederatedModules(federationPluginOptions as FederationConfig, outFile, typeDefinitions);
} else {
@@ -70,7 +78,7 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance {
// Import types from remote modules
const downloadTypesHook = async () => {
- return downloadTypes(remotes as Record, remoteManifestUrls);
+ return downloadTypes(dirEmittedTypes, dirDownloadedTypes, remotes as Record, remoteManifestUrls);
};
// Determine whether compilation of types should be performed continuously
diff --git a/src/types.ts b/src/types.ts
index 10d5a4c..ddce022 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -26,10 +26,14 @@ export type RemoteManifestUrls = Record<'registry' | string, string>;
export type ModuleFederationPluginOptions = ConstructorParameters[0];
export type ModuleFederationTypesPluginOptions = {
- cloudbedsRemoteManifestsBaseUrl?: string | 'use-domain-name',
+ dirEmittedTypes?: string,
+ dirGlobalTypes?: string;
+ dirDownloadedTypes?: string;
+
disableDownladingRemoteTypes?: boolean,
disableTypeCompilation?: boolean,
- doNotUseCloudbedsRemoteManifests?: boolean,
- remoteManifestUrls?: RemoteManifestUrls,
downloadTypesWhenIdleIntervalInSeconds?: number,
+ remoteManifestUrls?: RemoteManifestUrls,
+
+ cloudbedsRemoteManifestsBaseUrl?: string | 'use-domain-name',
}