feat: make webpack config asynchronous

This commit is contained in:
Eduardo Speroni
2021-11-19 18:37:46 -03:00
parent fa47eb47ff
commit eb219b1ee8
3 changed files with 29 additions and 25 deletions

View File

@@ -15,7 +15,7 @@ describe('@nativescript/webpack', () => {
expect(webpack.resolveConfig).toBeInstanceOf(Function);
});
it('applies chain configs', () => {
it('applies chain configs', async () => {
webpack.useConfig(false);
const chainFn = jest.fn();
@@ -26,13 +26,13 @@ describe('@nativescript/webpack', () => {
// chainFn should only be called when
// resolving a chainable config
const config = webpack.resolveChainableConfig();
const config = await webpack.resolveChainableConfig();
expect(chainFn).toHaveBeenCalledTimes(1);
expect(chainFn).toHaveBeenCalledWith(config, {});
});
it('applies chain configs in the right order', () => {
it('applies chain configs in the right order', async () => {
webpack.useConfig(false);
let lastCalled = false;
@@ -52,26 +52,29 @@ describe('@nativescript/webpack', () => {
});
webpack.chainWebpack(chainFnNormal);
webpack.resolveChainableConfig();
await webpack.resolveChainableConfig();
});
it('prints plugin name that has a chain function that throws an error', () => {
it('prints plugin name that has a chain function that throws an error', async () => {
webpack.useConfig(false);
webpack.setCurrentPlugin('test-plugin');
const chainFn = jest.fn(() => {
throw new Error('something wrong');
});
webpack.chainWebpack(chainFn);
let resolvable: Promise<any>;
// should not throw
expect(() => webpack.resolveChainableConfig()).not.toThrow();
expect(() => (resolvable = webpack.resolveChainableConfig())).not.toThrow();
expect(resolvable).resolves.toBeDefined();
await resolvable;
expect(
'Unable to apply chain function from: test-plugin'
).toHaveBeenWarned();
});
it('applies merge configs', () => {
it('applies merge configs', async () => {
const dummyEnv = { foo: true };
webpack.init(dummyEnv);
webpack.useConfig(false);
@@ -82,20 +85,20 @@ describe('@nativescript/webpack', () => {
// mergeFn should not be called yet
expect(mergeFn).not.toHaveBeenCalled();
const config = webpack.resolveChainableConfig();
const config = await webpack.resolveChainableConfig();
// mergeFn should not be called yet
expect(mergeFn).not.toHaveBeenCalled();
// mergeFn should only be called when
// resolving the final config
webpack.resolveConfig();
await webpack.resolveConfig();
expect(mergeFn).toHaveBeenCalledTimes(1);
expect(mergeFn).toHaveBeenCalledWith(config.toConfig(), dummyEnv);
});
it('merges mutate config', () => {
it('merges mutate config', async () => {
const dummyEnv = { foo: true };
webpack.init(dummyEnv);
webpack.useConfig(false);
@@ -104,12 +107,12 @@ describe('@nativescript/webpack', () => {
(config as any).mutated = true;
});
expect(webpack.resolveConfig()).toMatchObject({
expect(await webpack.resolveConfig()).toMatchObject({
mutated: true,
});
});
it('merges returned config', () => {
it('merges returned config', async () => {
const dummyEnv = { foo: true };
webpack.init(dummyEnv);
webpack.useConfig(false);
@@ -120,12 +123,12 @@ describe('@nativescript/webpack', () => {
};
});
expect(webpack.resolveConfig()).toMatchObject({
expect(await webpack.resolveConfig()).toMatchObject({
returned: true,
});
});
it('merges objects', () => {
it('merges objects', async () => {
const dummyEnv = { foo: true };
webpack.init(dummyEnv);
webpack.useConfig(false);
@@ -134,7 +137,7 @@ describe('@nativescript/webpack', () => {
object: true,
} as any);
expect(webpack.resolveConfig()).toMatchObject({
expect(await webpack.resolveConfig()).toMatchObject({
object: true,
});
});

View File

@@ -9,12 +9,12 @@ import * as lib from '../index';
/**
* @internal
*/
export function applyExternalConfigs() {
getAllDependencies().forEach((dependency) => {
export async function applyExternalConfigs() {
for (const dependency of getAllDependencies()) {
const packagePath = getDependencyPath(dependency);
if (!packagePath) {
return;
continue;
}
const configPath = path.join(packagePath, 'nativescript.webpack.js');
@@ -27,7 +27,7 @@ export function applyExternalConfigs() {
if (typeof externalConfig === 'function') {
info('Applying external config...');
externalConfig(lib);
await externalConfig(lib);
} else if (externalConfig) {
info('Merging external config...');
lib.mergeWebpack(externalConfig);
@@ -43,7 +43,7 @@ export function applyExternalConfigs() {
`);
}
}
});
}
clearCurrentPlugin();
}

View File

@@ -159,7 +159,7 @@ export function mergeWebpack(
/**
* Resolve a new instance of the internal chain config with all chain functions applied.
*/
export function resolveChainableConfig(): Config {
export async function resolveChainableConfig(): Promise<Config> {
const config = new Config();
if (!explicitUseConfig) {
@@ -168,7 +168,7 @@ export function resolveChainableConfig(): Config {
// apply configs from dependencies
// todo: allow opt-out
applyExternalConfigs();
await applyExternalConfigs();
webpackChains
.splice(0)
@@ -206,12 +206,13 @@ export function resolveChainableConfig(): Config {
*
* @param chainableConfig Optional chain config to use.
*/
export function resolveConfig(
chainableConfig = resolveChainableConfig()
): webpack.Configuration {
export async function resolveConfig(
chainableConfig: Config | Promise<Config> = resolveChainableConfig()
): Promise<webpack.Configuration> {
if (!hasInitialized) {
throw error('resolveConfig() must be called after init()');
}
chainableConfig = await chainableConfig;
let config = chainableConfig.toConfig();