@softarc/native-federation 4.0.0-RC9 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softarc/native-federation",
3
- "version": "4.0.0-RC9",
3
+ "version": "4.0.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -8,7 +8,7 @@
8
8
  "chalk": "^5.6.2",
9
9
  "fast-glob": "^3.3.3",
10
10
  "json5": "^2.2.3",
11
- "esbuild": "^0.27.0"
11
+ "esbuild": "^0.28.0"
12
12
  },
13
13
  "exports": {
14
14
  "./package.json": "./package.json",
package/src/internal.d.ts CHANGED
@@ -11,3 +11,5 @@ export type { NormalizedExternalConfig, NormalizedSharedExternalsConfig, } from
11
11
  export type { NormalizedFederationConfig } from './lib/domain/config/federation-config.contract.js';
12
12
  export { getDefaultCachePath, getChecksum } from './lib/utils/cache-persistence.js';
13
13
  export { isInSkipList, prepareSkipList } from './lib/config/default-skip-list.js';
14
+ export { NfFileWatcher, NfFileWatcherOptions } from './lib/domain/utils/file-watcher.contract.js';
15
+ export { syncNfFileWatcher, createNfWatcher } from './lib/utils/file-watcher.js';
package/src/internal.js CHANGED
@@ -8,3 +8,4 @@ export { createBuildResultMap, lookupInResultMap, popFromResultMap, } from './li
8
8
  export { writeImportMap } from './lib/core/write-import-map.js';
9
9
  export { getDefaultCachePath, getChecksum } from './lib/utils/cache-persistence.js';
10
10
  export { isInSkipList, prepareSkipList } from './lib/config/default-skip-list.js';
11
+ export { syncNfFileWatcher, createNfWatcher } from './lib/utils/file-watcher.js';
@@ -55,7 +55,10 @@ export async function bundleExposedAndMappings(config, fedOptions, externals, mo
55
55
  }
56
56
  throw error;
57
57
  }
58
- const resultMap = createBuildResultMap(result, hash);
58
+ const resultMap = createBuildResultMap(result, hash, [
59
+ ...shared.map(s => s.outName),
60
+ ...exposes.map(e => e.outName),
61
+ ]);
59
62
  const sharedResult = [];
60
63
  const entryFiles = [];
61
64
  // Pick shared-mappings
@@ -27,6 +27,7 @@ export async function normalizeFederationOptions(options, cache) {
27
27
  ...options,
28
28
  entryPoints: options.entryPoints ?? Object.values(config.exposes ?? {}),
29
29
  projectName: resolveProjectName(options.projectName ?? config.name),
30
+ cacheExternalArtifacts: options.cacheExternalArtifacts ?? true,
30
31
  federationCache,
31
32
  };
32
33
  /**
@@ -46,11 +47,6 @@ export async function normalizeFederationOptions(options, cache) {
46
47
  .reduce((acc, [_path, _import]) => ({ ...acc, [_path]: _import }), {});
47
48
  }
48
49
  }
49
- /**
50
- * Step 4: Verify imports
51
- */
52
- checkForInvalidImports(Object.values(config.sharedMappings), 'shared mappings');
53
- checkForInvalidImports(Object.keys(config.shared), 'externals');
54
50
  return { config, options: normalizedOptions };
55
51
  }
56
52
  export function resolveProjectName(name) {
@@ -60,31 +56,3 @@ export function resolveProjectName(name) {
60
56
  }
61
57
  return normalizePackageName(name);
62
58
  }
63
- const ALLOWED_FILE_EXTENSIONS = new Set(['mjs', 'js', 'mts', 'ts', 'jsx', 'tsx', 'json']);
64
- function checkForInvalidImports(importList, type) {
65
- const importsWithDot = [];
66
- for (const mappingImport of importList) {
67
- if (mappingImport.indexOf('.') < 0) {
68
- continue;
69
- }
70
- const queryIndex = mappingImport.search(/[?#]/);
71
- const sanitizedImport = queryIndex >= 0 ? mappingImport.slice(0, queryIndex) : mappingImport;
72
- const segmentStart = sanitizedImport.lastIndexOf('/') + 1;
73
- const dotIndex = sanitizedImport.lastIndexOf('.');
74
- if (dotIndex < segmentStart) {
75
- importsWithDot.push(mappingImport);
76
- continue;
77
- }
78
- const extension = sanitizedImport.slice(dotIndex + 1);
79
- if (!ALLOWED_FILE_EXTENSIONS.has(extension)) {
80
- importsWithDot.push(mappingImport);
81
- }
82
- }
83
- if (importsWithDot.length > 0) {
84
- importsWithDot.forEach(e => {
85
- logger.warn(`Import '${e}' contains a bad dot (.) import.`);
86
- });
87
- logger.debug('Bad import issue: https://github.com/vitejs/vite/issues/21036');
88
- throw new Error(`Invalid '${type}' config. Invalid imports paths detected, consider using a barrel import instead. `);
89
- }
90
- }
@@ -18,4 +18,5 @@ export interface NormalizedFederationOptions<TBundlerCache = unknown> extends Fe
18
18
  federationCache: FederationCache<TBundlerCache>;
19
19
  entryPoints: string[];
20
20
  projectName: string;
21
+ cacheExternalArtifacts: boolean;
21
22
  }
@@ -0,0 +1,10 @@
1
+ export interface NfFileWatcherOptions {
2
+ onChange?: (path: string) => void;
3
+ }
4
+ export interface NfFileWatcher {
5
+ addPaths(paths: string | readonly string[]): void;
6
+ close(): Promise<void>;
7
+ get(): ReadonlySet<string>;
8
+ clear(): void;
9
+ mutate(fn: (dirtyPaths: Set<string>) => void): void;
10
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
1
  import type { NFBuildAdapterResult } from '../domain/core/build-adapter.contract.js';
2
- export declare function createBuildResultMap(buildResult: NFBuildAdapterResult[], isHashed: boolean): Record<string, string>;
2
+ export declare function createBuildResultMap(buildResult: NFBuildAdapterResult[], isHashed: boolean, expectedNames?: string[]): Record<string, string>;
3
3
  export declare function lookupInResultMap(map: Record<string, string>, requestName: string): string;
4
4
  export declare function popFromResultMap(map: Record<string, string>, requestName: string): string;
@@ -1,16 +1,17 @@
1
1
  import path from 'path';
2
- export function createBuildResultMap(buildResult, isHashed) {
2
+ function stripHash(fileName) {
3
+ const start = fileName.lastIndexOf('-');
4
+ const end = fileName.lastIndexOf('.');
5
+ if (start < 0 || end < 0 || start > end)
6
+ return fileName;
7
+ return fileName.substring(0, start) + fileName.substring(end);
8
+ }
9
+ export function createBuildResultMap(buildResult, isHashed, expectedNames = []) {
10
+ const expected = new Set(expectedNames.map(n => path.basename(n)));
3
11
  const map = {};
4
12
  for (const item of buildResult) {
5
13
  const resultName = path.basename(item.fileName);
6
- let requestName = resultName;
7
- if (isHashed) {
8
- const start = resultName.lastIndexOf('-');
9
- const end = resultName.lastIndexOf('.');
10
- const part1 = resultName.substring(0, start);
11
- const part2 = resultName.substring(end);
12
- requestName = part1 + part2;
13
- }
14
+ const requestName = isHashed && expected.has(stripHash(resultName)) ? stripHash(resultName) : resultName;
14
15
  map[requestName] = item.fileName;
15
16
  }
16
17
  return map;
@@ -0,0 +1,5 @@
1
+ import type { NfFileWatcher, NfFileWatcherOptions } from '../domain/utils/file-watcher.contract.js';
2
+ export declare function createNfWatcher(options?: NfFileWatcherOptions): NfFileWatcher;
3
+ export declare function syncNfFileWatcher(watcher: NfFileWatcher, bundlerCache: {
4
+ keys(): IterableIterator<string>;
5
+ }): void;
@@ -0,0 +1,51 @@
1
+ import { logger } from '@softarc/native-federation/internal';
2
+ import { watch, statSync } from 'fs';
3
+ import { join } from 'path';
4
+ const toUnix = (p) => p.replace(/\\/g, '/');
5
+ export function createNfWatcher(options = {}) {
6
+ const { onChange } = options;
7
+ const watchers = new Map();
8
+ const dirtyPaths = new Set();
9
+ const notify = (path) => {
10
+ if (onChange)
11
+ onChange(path);
12
+ else
13
+ dirtyPaths.add(path);
14
+ };
15
+ return {
16
+ addPaths(paths) {
17
+ const list = typeof paths === 'string' ? [paths] : [...paths];
18
+ for (const p of list) {
19
+ if (watchers.has(p))
20
+ continue;
21
+ try {
22
+ const isDir = statSync(p).isDirectory();
23
+ const w = isDir
24
+ ? watch(p, { recursive: true }, (_, filename) => {
25
+ if (filename)
26
+ notify(toUnix(join(p, filename)));
27
+ })
28
+ : watch(p, () => notify(toUnix(p)));
29
+ watchers.set(p, w);
30
+ }
31
+ catch {
32
+ logger.debug(`Could not watch path '${p}'.`);
33
+ }
34
+ }
35
+ },
36
+ get: () => dirtyPaths,
37
+ clear: () => dirtyPaths.clear(),
38
+ mutate: fn => fn(dirtyPaths),
39
+ async close() {
40
+ for (const w of watchers.values()) {
41
+ w.close();
42
+ }
43
+ watchers.clear();
44
+ },
45
+ };
46
+ }
47
+ export function syncNfFileWatcher(watcher, bundlerCache) {
48
+ const files = [...bundlerCache.keys()].filter(k => !k.includes('node_modules'));
49
+ if (files.length)
50
+ watcher.addPaths(files);
51
+ }