-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added download-federated-types script
- Loading branch information
1 parent
b969be0
commit 15a3500
Showing
46 changed files
with
907 additions
and
437 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,7 @@ node_modules | |
# Mac | ||
*.DS_Store | ||
**/*.DS_Store | ||
|
||
# Tests | ||
coverage | ||
report.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import { | ||
DEFAULT_DIR_DOWNLOADED_TYPES, DEFAULT_DIR_EMITTED_TYPES, | ||
} from '../../constants'; | ||
import { | ||
downloadTypes, getRemoteManifestUrls, | ||
} from '../../downloadTypes'; | ||
import { getOptionsFromWebpackConfig } from '../helpers'; | ||
|
||
jest.mock('minimist', () => (args: string[]) => { | ||
const webpackConfigIndex = args.findIndex(arg => arg === '--webpack-config'); | ||
return webpackConfigIndex > -1 | ||
? { 'webpack-config': args[webpackConfigIndex + 1] } | ||
: {}; | ||
}); | ||
jest.mock('../../downloadTypes', () => ({ | ||
downloadTypes: jest.fn(), | ||
getRemoteManifestUrls: jest.fn(), | ||
})); | ||
jest.mock('../helpers', () => ({ | ||
assertRunningFromRoot: jest.fn(() => true), | ||
getOptionsFromWebpackConfig: jest.fn(), | ||
})); | ||
|
||
const mockDownloadTypes = downloadTypes as jest.MockedFunction<typeof downloadTypes>; | ||
const mockGetOptionsFromWebpackConfig = getOptionsFromWebpackConfig as jest | ||
.MockedFunction<typeof getOptionsFromWebpackConfig>; | ||
const mockGetRemoteManifestUrls = getRemoteManifestUrls as jest | ||
.MockedFunction<typeof getRemoteManifestUrls>; | ||
|
||
const validOptions: ReturnType<typeof getOptionsFromWebpackConfig> = { | ||
mfPluginOptions: { | ||
remotes: { | ||
app1: 'app1@https://app1-url/remoteEntry.js', | ||
app2: 'app1@https://app2-url/remoteEntry.js', | ||
}, | ||
}, | ||
mfTypesPluginOptions: { | ||
remoteEntryUrls: { url1: 'http://valid-url' }, | ||
dirDownloadedTypes: 'custom-dist/types', | ||
dirEmittedTypes: 'src/@wmf-types/types', | ||
}, | ||
}; | ||
|
||
describe('download-federated-types', () => { | ||
const originalArgv = process.argv; | ||
const originalProcessExit = process.exit; | ||
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(); | ||
const mockConsoleError = jest.spyOn(console, 'error').mockImplementation(); | ||
process.exit = jest.fn() as never; | ||
|
||
beforeEach(() => { | ||
process.argv = ['node', 'download-federated-types']; | ||
|
||
mockGetRemoteManifestUrls.mockReturnValue({}); | ||
mockGetOptionsFromWebpackConfig.mockReturnValue({ | ||
mfPluginOptions: {}, | ||
mfTypesPluginOptions: {}, | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
process.argv = originalArgv; | ||
}); | ||
|
||
afterAll(() => { | ||
process.exit = originalProcessExit; | ||
}); | ||
|
||
test('exits when remote URL is invalid', () => { | ||
const remoteEntryUrls = { url1: 'invalid-url' }; | ||
mockGetOptionsFromWebpackConfig.mockReturnValue({ | ||
mfPluginOptions: {}, | ||
mfTypesPluginOptions: { | ||
remoteEntryUrls, | ||
}, | ||
}); | ||
|
||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
|
||
expect(mockGetOptionsFromWebpackConfig).toHaveBeenCalledWith('webpack/prod.ts'); | ||
expect(mockConsoleError).toHaveBeenCalledWith('One or more remote URLs are invalid:', remoteEntryUrls); | ||
expect(process.exit).toHaveBeenCalledWith(1); | ||
}); | ||
|
||
test('exits when remote manifest URL is invalid', () => { | ||
const manifestUrls = { url1: 'invalid-url' }; | ||
mockGetRemoteManifestUrls.mockReturnValue(manifestUrls); | ||
|
||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
|
||
expect(mockGetRemoteManifestUrls).toHaveBeenCalled(); | ||
expect(process.exit).toHaveBeenCalledWith(1); | ||
expect(mockConsoleError).toHaveBeenCalledWith('One or more remote manifest URLs are invalid:', manifestUrls); | ||
}); | ||
|
||
test('calls downloadTypes with correct arguments and logs success on valid URLs', async () => { | ||
const manifestUrls = { url1: 'https://manifest-registry' }; | ||
mockGetRemoteManifestUrls.mockReturnValue(manifestUrls); | ||
mockGetOptionsFromWebpackConfig.mockReturnValue(validOptions); | ||
|
||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
await Promise.resolve(); | ||
|
||
expect(mockDownloadTypes).toHaveBeenCalledWith( | ||
validOptions.mfTypesPluginOptions.dirEmittedTypes, | ||
validOptions.mfTypesPluginOptions.dirDownloadedTypes, | ||
validOptions.mfPluginOptions.remotes, | ||
validOptions.mfTypesPluginOptions.remoteEntryUrls, | ||
manifestUrls, | ||
); | ||
expect(mockConsoleLog).toHaveBeenCalledWith('Successfully downloaded federated types.'); | ||
}); | ||
|
||
test('exits with error when downloadTypes throws an error', async () => { | ||
mockDownloadTypes.mockRejectedValue(new Error('Error downloading types')); | ||
|
||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
await Promise.resolve(); | ||
|
||
expect(mockConsoleError).toHaveBeenCalledWith('Error downloading federated types:', expect.any(Error)); | ||
expect(process.exit).toHaveBeenCalledWith(1); | ||
}); | ||
|
||
test('uses default directories when mfTypesPluginOptions does not provide them', () => { | ||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
|
||
expect(mockDownloadTypes).toHaveBeenCalledWith( | ||
DEFAULT_DIR_EMITTED_TYPES, | ||
DEFAULT_DIR_DOWNLOADED_TYPES, | ||
undefined, | ||
undefined, | ||
{}, | ||
); | ||
}); | ||
|
||
test('parses argv and uses custom webpack config path', () => { | ||
process.argv[2] = '--webpack-config'; | ||
process.argv[3] = 'custom/webpack.config.ts'; | ||
|
||
jest.isolateModules(() => { | ||
require('../download-federated-types'); | ||
}); | ||
|
||
expect(mockGetOptionsFromWebpackConfig).toHaveBeenCalledWith('custom/webpack.config.ts'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#!/usr/bin/env node | ||
|
||
import parseArgs from 'minimist'; | ||
|
||
import { | ||
DEFAULT_DIR_DOWNLOADED_TYPES, DEFAULT_DIR_EMITTED_TYPES, | ||
} from '../constants'; | ||
import { | ||
downloadTypes, getRemoteManifestUrls, | ||
} from '../downloadTypes'; | ||
import { | ||
isEveryUrlValid, setLogger, | ||
} from '../helpers'; | ||
|
||
import { | ||
assertRunningFromRoot, getOptionsFromWebpackConfig, | ||
} from './helpers'; | ||
|
||
assertRunningFromRoot(); | ||
|
||
type Argv = { | ||
'webpack-config'?: string, | ||
}; | ||
|
||
const argv = parseArgs<Argv>(process.argv.slice(2)); | ||
const webpackConfigPath = argv['webpack-config'] || 'webpack/prod.ts'; | ||
|
||
const { mfPluginOptions, mfTypesPluginOptions } = getOptionsFromWebpackConfig(webpackConfigPath); | ||
|
||
const remoteManifestUrls = getRemoteManifestUrls(mfTypesPluginOptions)!; | ||
|
||
if (!isEveryUrlValid(Object.values({ ...mfTypesPluginOptions.remoteEntryUrls }))) { | ||
console.error('One or more remote URLs are invalid:', mfTypesPluginOptions.remoteEntryUrls); | ||
process.exit(1); | ||
} | ||
if (!isEveryUrlValid(Object.values({ ...remoteManifestUrls }))) { | ||
console.error('One or more remote manifest URLs are invalid:', remoteManifestUrls); | ||
process.exit(1); | ||
} | ||
|
||
(async () => { | ||
setLogger(console); | ||
|
||
try { | ||
await downloadTypes( | ||
mfTypesPluginOptions?.dirEmittedTypes || DEFAULT_DIR_EMITTED_TYPES, | ||
mfTypesPluginOptions?.dirDownloadedTypes || DEFAULT_DIR_DOWNLOADED_TYPES, | ||
mfPluginOptions.remotes, | ||
mfTypesPluginOptions.remoteEntryUrls, | ||
remoteManifestUrls, | ||
); | ||
console.log('Successfully downloaded federated types.'); | ||
} catch (error) { | ||
console.error('Error downloading federated types:', error); | ||
process.exit(1); | ||
} | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import fs from 'fs'; | ||
|
||
export function assertRunningFromRoot(): void { | ||
if (!fs.readdirSync('./').includes('node_modules')) { | ||
console.error('ERROR: Script must be run from the root directory of the project'); | ||
process.exit(1); | ||
} | ||
} |
12 changes: 2 additions & 10 deletions
12
src/helpers/cli.ts → src/bin/helpers/getFederationConfig.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Compiler } from 'webpack'; | ||
|
||
import { ModuleFederationTypesPluginOptions } from '../../models'; | ||
|
||
export function getOptionsFromWebpackConfig(webpackConfigPath: string) { | ||
let webpackConfig: Compiler['options']; | ||
try { | ||
webpackConfig = require(webpackConfigPath); | ||
webpackConfig = ((webpackConfig as unknown as Dict).default as Compiler['options']) || webpackConfig; | ||
} catch (error) { | ||
console.error(`Failed to import webpack config from ${webpackConfigPath}:`, error); | ||
process.exit(1); | ||
} | ||
|
||
if (!webpackConfig) { | ||
console.error(`Empty webpack config loaded from ${webpackConfigPath}`); | ||
process.exit(1); | ||
} | ||
|
||
function getModuleFederationPluginOptions(config: Compiler['options']) { | ||
const plugin = config.plugins.find( | ||
nextPlugin => nextPlugin!.constructor.name === 'ModuleFederationPlugin', | ||
); | ||
// eslint-disable-next-line no-underscore-dangle | ||
return (plugin as Dict)?._options as Dict & { remotes?: Dict<string> }; | ||
} | ||
|
||
function getModuleFederationTypesPluginOptions(config: Compiler['options']) { | ||
const plugin = config.plugins.find( | ||
nextPlugin => nextPlugin!.constructor.name === 'ModuleFederationTypesPlugin', | ||
); | ||
return (plugin as Dict)?.options as ModuleFederationTypesPluginOptions; | ||
} | ||
|
||
const mfPluginOptions = getModuleFederationPluginOptions(webpackConfig); | ||
const mfTypesPluginOptions = getModuleFederationTypesPluginOptions(webpackConfig); | ||
|
||
if (!mfTypesPluginOptions || !mfPluginOptions) { | ||
console.error('Could not find required ModuleFederation plugin options in the webpack config.'); | ||
process.exit(1); | ||
} | ||
|
||
return { | ||
mfPluginOptions, | ||
mfTypesPluginOptions, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './assertRunningFromRoot'; | ||
export * from './getFederationConfig'; | ||
export * from './getOptionsFromWebpackConfig'; |
Oops, something went wrong.