Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

refactor: bundling external fallbacks with webpack #637

Closed
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ lerna-debug.log
test-results
.jest-cache
bundle.integrity.manifest.json
packages/**/__tests__/**/build

# intelliJ
.idea/
Expand Down
1 change: 1 addition & 0 deletions jest.esm.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = {
collectCoverageFrom: [
'packages/**/*.{mjs,js,jsx}',
'!**/__test_fixtures__/**',
'!**/__fixtures__/**',
'!**/node_modules/**',
'!**/build/**',
'!packages/*/bin/**',
Expand Down
14 changes: 13 additions & 1 deletion packages/one-app-bundler/__tests__/bin/bundle-module.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,27 @@
/* eslint-disable global-require --
testing `on import` functionality needs 'require' in every tests */

jest.mock('read-package-up', () => ({
readPackageUpSync: () => ({
packageJson: {
name: 'my-module-name',
version: '1.2.3',
},
}),
}));

jest.mock('@americanexpress/one-app-dev-bundler', () => ({
devBuildModule: async () => undefined,
bundleExternalFallbacks: async () => undefined,
}));

jest.mock('../../bin/webpack-bundle-module', () => ({
webpackBundleModule: jest.fn(),
}));

jest.mock('../../bin/bundle-external-fallbacks', () => ({
bundleExternalFallbacks: jest.fn(),
}));

jest.spyOn(console, 'info');

describe('bundle-module', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

import { getExternalLibraryName } from '../../utils/getExternalLibraryName';

describe('getExternalLibraryName', () => {
it('creates a library name using an external name and version', () => {
expect(getExternalLibraryName('@amex/test-lib', '1.2.3')).toBe('__holocron_external__amex_test_lib__1_2_3');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

import fs from 'node:fs';
import { writeToModuleConfig } from '../../utils/writeToModuleConfig';

jest.mock('node:fs', () => ({
writeFileSync: jest.fn(),
readFileSync: jest.fn(() => JSON.stringify({})),
existsSync: jest.fn(),
}));

jest.mock('read-package-up', () => ({
readPackageUpSync: () => ({
packageJson: {
name: 'my-module-name',
version: '1.2.3',
},
}),
}));

describe('write-to-module-config', () => {
beforeAll(() => {
process.cwd = () => '/mock-path';
});

beforeEach(() => {
jest.clearAllMocks();
});

describe('module-config.json does not exist', () => {
beforeEach(() => {
fs.existsSync.mockImplementation(() => false);
});

it('successfully writes to module config', () => {
writeToModuleConfig({ my: 'module-config' });
expect(fs.writeFileSync).toHaveBeenCalledWith('/mock-path/build/1.2.3/module-config.json', '{\n "my": "module-config"\n}');
});
});

describe('module-config.json exists', () => {
beforeEach(() => {
fs.existsSync.mockImplementation(() => true);
fs.readFileSync.mockImplementation(() => JSON.stringify({
hello: 'im here',
}));
});

it('successfully writes to module config', () => {
writeToModuleConfig({ my: 'module-config' });
expect(fs.writeFileSync).toHaveBeenCalledWith(
'/mock-path/build/1.2.3/module-config.json',
'{\n "hello": "im here",\n "my": "module-config"\n}'
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`webpack/module.client should generate full list of fall backs 1`] = `
Object {
"assert": "/mock/path/for/request/assert",
"buffer": "/mock/path/for/request/buffer",
"console": "/mock/path/for/request/console-browserify",
"constants": "/mock/path/for/request/constants-browserify",
"crypto": "/mock/path/for/request/crypto-browserify",
"domain": "/mock/path/for/request/domain-browser",
"events": "/mock/path/for/request/events",
"http": "/mock/path/for/request/stream-http",
"https": "/mock/path/for/request/https-browserify",
"os": "/mock/path/for/request/os-browserify/browser",
"path": "/mock/path/for/request/path-browserify",
"process": "/mock/path/for/request/process/browser",
"punycode": "/mock/path/for/request/punycode",
"querystring": "/mock/path/for/request/querystring-es3",
"stream": "/mock/path/for/request/stream-browserify",
"string_decoder": "/mock/path/for/request/string_decoder",
"sys": "/mock/path/for/request/util",
"timers": "/mock/path/for/request/timers-browserify",
"tty": "/mock/path/for/request/tty-browserify",
"url": "/mock/path/for/request/url",
"util": "/mock/path/for/request/util",
"vm": "/mock/path/for/request/vm-browserify",
"zlib": "/mock/path/for/request/browserify-zlib",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

import path from 'node:path';
import { validateWebpackConfig } from '../../../test-utils.js';
import webpackClientConfig from '../../../webpack/externalFallbacks/webpack.client.js';

jest.mock('@americanexpress/one-app-dev-bundler', () => ({ BUNDLE_TYPES: { BROWSER: 'BROWSER_BUILD_TYPE', SERVER: 'SERVER_BUILD_TYPE' } }));

jest.spyOn(process, 'cwd').mockImplementation(() => __dirname.split(`${path.sep}__tests__`)[0]);

jest.mock('node:url', () => ({
fileURLToPath: jest.fn((url) => `/mock/path/for/url/${url}`),
}));

// Mock out create resolver to return a mock path for the webpack 4 pollyfill resolves.
jest.mock('../../../webpack/createResolver.js', () => jest.fn(() => jest.fn((request) => `/mock/path/for/request/${request}`)));

jest.mock('read-package-up', () => ({
readPackageUpSync: jest.fn(() => ({
packageJson: {
name: 'package-name-mock',
version: '1.2.3-version-mock',
},
})),
}));

describe('webpack/module.client', () => {
let originalNodeEnv;
beforeAll(() => { originalNodeEnv = process.env.NODE_ENV; });
afterAll(() => { process.env.NODE_ENV = originalNodeEnv; });

it('should export valid webpack config', async () => {
expect.assertions(1);
const webpackConfig = await webpackClientConfig('external-a', '1.2.3');
expect(() => validateWebpackConfig(webpackConfig)).not.toThrow();
});

it('should generate full list of fall backs', async () => {
expect.assertions(2);
const webpackConfig = await webpackClientConfig('external-a', '1.2.3');
expect(() => validateWebpackConfig(webpackConfig)).not.toThrow();
expect(webpackConfig.resolve.fallback).toMatchSnapshot();
});

it('should define global.BROWSER to be true', async () => {
expect.assertions(2);
const webpackConfig = await webpackClientConfig('external-a', '1.2.3');
expect(webpackConfig).toHaveProperty('plugins', expect.any(Array));
expect(webpackConfig.plugins).toContainEqual({ definitions: { global: 'globalThis', 'global.BROWSER': 'true' } });
});

it('should append holocronModule with name', async () => {
expect.assertions(1);
const webpackConfig = await webpackClientConfig('external-a', '1.2.3');
expect(webpackConfig.output.library).toBe('__holocron_external__external_a__1_2_3');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

import webpackServerConfig from '../../../webpack/externalFallbacks/webpack.server.js';
import { validateWebpackConfig } from '../../../test-utils.js';

jest.mock('@americanexpress/one-app-dev-bundler', () => ({ BUNDLE_TYPES: { BROWSER: 'BROWSER_BUILD_TYPE', SERVER: 'SERVER_BUILD_TYPE' } }));

jest.spyOn(process, 'cwd').mockImplementation(() => __dirname.split('/__tests__')[0]);

jest.mock('node:url', () => ({
fileURLToPath: jest.fn((url) => `/mock/path/for/url/${url}`),
}));

jest.mock('read-package-up', () => ({
readPackageUpSync: jest.fn(() => ({ packageJson: { name: '@americanexpress/one-app-bundler', version: '6.8.0' } })),
}));

describe('webpack/module.server', () => {
it('should export valid webpack config', async () => {
expect.assertions(1);
await expect(async () => validateWebpackConfig(await webpackServerConfig('external-a'))).not.toThrow();
});

it('should define global.BROWSER to be false', async () => {
expect.assertions(2);
expect(await webpackServerConfig('external-a')).toHaveProperty('plugins', expect.any(Array));
expect((await webpackServerConfig('external-a')).plugins).toContainEqual({ definitions: { global: 'globalThis', 'global.BROWSER': 'false' } });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

const ID = 'external-a';

export const ExternalA = () => {
console.log('hello mundo!');

return ID;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations
* under the License.
*/

export { ExternalA } from './external-a.js';