feat(webpack): generate React and Web apps with webpack.config.js file (#14285)
This commit is contained in:
parent
0925c294d1
commit
454fba49b2
35
e2e/node/src/node-esbuild.test.ts
Normal file
35
e2e/node/src/node-esbuild.test.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {
|
||||||
|
checkFilesDoNotExist,
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
newProject,
|
||||||
|
runCLI,
|
||||||
|
runCLIAsync,
|
||||||
|
tmpProjPath,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
} from '@nrwl/e2e/utils';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
|
describe('Node Applications + esbuild', () => {
|
||||||
|
beforeEach(() => newProject());
|
||||||
|
|
||||||
|
afterEach(() => cleanupProject());
|
||||||
|
|
||||||
|
it('should generate an app using esbuild', async () => {
|
||||||
|
const app = uniq('nodeapp');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/node:app ${app} --bundler=esbuild --no-interactive`);
|
||||||
|
|
||||||
|
checkFilesDoNotExist(`apps/${app}/webpack.config.js`);
|
||||||
|
|
||||||
|
updateFile(`apps/${app}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
|
await runCLIAsync(`build ${app}`);
|
||||||
|
|
||||||
|
checkFilesExist(`dist/apps/${app}/main.cjs`);
|
||||||
|
const result = execSync(`node dist/apps/${app}/main.cjs`, {
|
||||||
|
cwd: tmpProjPath(),
|
||||||
|
}).toString();
|
||||||
|
expect(result).toMatch(/Hello World!/);
|
||||||
|
}, 300_000);
|
||||||
|
});
|
||||||
35
e2e/node/src/node-webpack.test.ts
Normal file
35
e2e/node/src/node-webpack.test.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {
|
||||||
|
checkFilesDoNotExist,
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
newProject,
|
||||||
|
runCLI,
|
||||||
|
runCLIAsync,
|
||||||
|
tmpProjPath,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
} from '@nrwl/e2e/utils';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
|
describe('Node Applications + webpack', () => {
|
||||||
|
beforeEach(() => newProject());
|
||||||
|
|
||||||
|
afterEach(() => cleanupProject());
|
||||||
|
|
||||||
|
it('should generate an app using webpack', async () => {
|
||||||
|
const app = uniq('nodeapp');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/node:app ${app} --bundler=webpack --no-interactive`);
|
||||||
|
|
||||||
|
checkFilesExist(`apps/${app}/webpack.config.js`);
|
||||||
|
|
||||||
|
updateFile(`apps/${app}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
|
await runCLIAsync(`build ${app}`);
|
||||||
|
|
||||||
|
checkFilesExist(`dist/apps/${app}/main.js`);
|
||||||
|
const result = execSync(`node dist/apps/${app}/main.js`, {
|
||||||
|
cwd: tmpProjPath(),
|
||||||
|
}).toString();
|
||||||
|
expect(result).toMatch(/Hello World!/);
|
||||||
|
}, 300_000);
|
||||||
|
});
|
||||||
@ -59,8 +59,8 @@ describe('Node Applications', () => {
|
|||||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
await runCLIAsync(`build ${nodeapp}`);
|
await runCLIAsync(`build ${nodeapp}`);
|
||||||
|
|
||||||
checkFilesExist(`dist/apps/${nodeapp}/main.js`);
|
checkFilesExist(`dist/apps/${nodeapp}/main.cjs`);
|
||||||
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
|
const result = execSync(`node dist/apps/${nodeapp}/main.cjs`, {
|
||||||
cwd: tmpProjPath(),
|
cwd: tmpProjPath(),
|
||||||
}).toString();
|
}).toString();
|
||||||
expect(result).toContain('Hello World!');
|
expect(result).toContain('Hello World!');
|
||||||
@ -76,13 +76,15 @@ describe('Node Applications', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await runCLIAsync(`build ${nodeapp}`);
|
await runCLIAsync(`build ${nodeapp}`);
|
||||||
checkFilesExist(`dist/apps/${nodeapp}/index.js`);
|
checkFilesExist(`dist/apps/${nodeapp}/index.cjs`);
|
||||||
}, 300000);
|
}, 300000);
|
||||||
|
|
||||||
it('should be able to generate an empty application with additional entries', async () => {
|
it('should be able to generate an empty application with additional entries', async () => {
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
|
|
||||||
runCLI(`generate @nrwl/node:app ${nodeapp} --linter=eslint`);
|
runCLI(
|
||||||
|
`generate @nrwl/node:app ${nodeapp} --linter=eslint --bundler=webpack`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
@ -267,7 +269,7 @@ describe('Build Node apps', () => {
|
|||||||
expect(satisfies(packageJson.dependencies['tslib'], '^2.3.0')).toBeTruthy();
|
expect(satisfies(packageJson.dependencies['tslib'], '^2.3.0')).toBeTruthy();
|
||||||
|
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
runCLI(`generate @nrwl/node:app ${nodeapp}`);
|
runCLI(`generate @nrwl/node:app ${nodeapp} --bundler=webpack`);
|
||||||
|
|
||||||
const jslib = uniq('jslib');
|
const jslib = uniq('jslib');
|
||||||
runCLI(`generate @nrwl/js:lib ${jslib} --buildable`);
|
runCLI(`generate @nrwl/js:lib ${jslib} --buildable`);
|
||||||
|
|||||||
@ -48,19 +48,26 @@ describe('React Module Federation', () => {
|
|||||||
updateFile(
|
updateFile(
|
||||||
`apps/${shell}/webpack.config.js`,
|
`apps/${shell}/webpack.config.js`,
|
||||||
stripIndents`
|
stripIndents`
|
||||||
const { withModuleFederation } = require('@nrwl/react/module-federation');
|
import { ModuleFederationConfig } from '@nrwl/devkit';
|
||||||
const moduleFederationConfig = require('./module-federation.config');
|
import { composePlugins, withNx } from '@nrwl/webpack';
|
||||||
|
import { withReact } from '@nrwl/react';
|
||||||
module.exports = withModuleFederation({
|
import { withModuleFederation } from '@nrwl/react/module-federation');
|
||||||
...moduleFederationConfig,
|
|
||||||
remotes: [
|
const baseConfig = require('./module-federation.config');
|
||||||
'${remote1}',
|
|
||||||
['${remote2}', 'http://localhost:${readPort(
|
const config: ModuleFederationConfig = {
|
||||||
|
...baseConfig,
|
||||||
|
remotes: [
|
||||||
|
'${remote1}',
|
||||||
|
['${remote2}', 'http://localhost:${readPort(
|
||||||
remote2
|
remote2
|
||||||
)}/remoteEntry.js'],
|
)}/remoteEntry.js'],
|
||||||
['${remote3}', 'http://localhost:${readPort(remote3)}'],
|
['${remote3}', 'http://localhost:${readPort(remote3)}'],
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config));
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
const initTask = await initGenerator(tree, { ...options, skipFormat: true });
|
const initTask = await initGenerator(tree, { ...options, skipFormat: true });
|
||||||
const applicationTask = await nodeApplicationGenerator(tree, {
|
const applicationTask = await nodeApplicationGenerator(tree, {
|
||||||
...schema,
|
...schema,
|
||||||
|
bundler: 'webpack',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
addMainFile(tree, options);
|
addMainFile(tree, options);
|
||||||
|
|||||||
@ -43,5 +43,6 @@ export function toNodeApplicationGeneratorOptions(
|
|||||||
tags: options.tags,
|
tags: options.tags,
|
||||||
unitTestRunner: options.unitTestRunner,
|
unitTestRunner: options.unitTestRunner,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
|
bundler: 'webpack', // Some features require webpack plugins such as TS transformers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import * as devkit from '@nrwl/devkit';
|
import * as devkit from '@nrwl/devkit';
|
||||||
import { getProjects, NxJsonConfiguration, readJson, Tree } from '@nrwl/devkit';
|
import {
|
||||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
getProjects,
|
||||||
|
readJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
import { applicationGenerator as angularApplicationGenerator } from '@nrwl/angular/generators';
|
import { applicationGenerator as angularApplicationGenerator } from '@nrwl/angular/generators';
|
||||||
@ -13,7 +18,7 @@ describe('app', () => {
|
|||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
tree = createTreeWithEmptyV1Workspace();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
|
||||||
overrideCollectionResolutionForTesting({
|
overrideCollectionResolutionForTesting({
|
||||||
'@nrwl/cypress': join(__dirname, '../../../../cypress/generators.json'),
|
'@nrwl/cypress': join(__dirname, '../../../../cypress/generators.json'),
|
||||||
@ -32,27 +37,26 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update workspace.json', async () => {
|
it('should update project config', async () => {
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'myNodeApp',
|
name: 'myNodeApp',
|
||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
const workspaceJson = readJson(tree, '/workspace.json');
|
const project = readProjectConfiguration(tree, 'my-node-app');
|
||||||
const nxJson = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
expect(project.root).toEqual('my-node-app');
|
||||||
const project = workspaceJson.projects['my-node-app'];
|
expect(project.targets).toEqual(
|
||||||
expect(project.root).toEqual('apps/my-node-app');
|
|
||||||
expect(project.architect).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
build: {
|
build: {
|
||||||
builder: '@nrwl/webpack:webpack',
|
executor: '@nrwl/webpack:webpack',
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
target: 'node',
|
target: 'node',
|
||||||
compiler: 'tsc',
|
compiler: 'tsc',
|
||||||
outputPath: 'dist/apps/my-node-app',
|
outputPath: 'dist/my-node-app',
|
||||||
main: 'apps/my-node-app/src/main.ts',
|
main: 'my-node-app/src/main.ts',
|
||||||
tsConfig: 'apps/my-node-app/tsconfig.app.json',
|
tsConfig: 'my-node-app/tsconfig.app.json',
|
||||||
assets: ['apps/my-node-app/src/assets'],
|
webpackConfig: 'my-node-app/webpack.config.js',
|
||||||
|
assets: ['my-node-app/src/assets'],
|
||||||
},
|
},
|
||||||
configurations: {
|
configurations: {
|
||||||
production: {
|
production: {
|
||||||
@ -63,7 +67,7 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
serve: {
|
serve: {
|
||||||
builder: '@nrwl/js:node',
|
executor: '@nrwl/js:node',
|
||||||
options: {
|
options: {
|
||||||
buildTarget: 'my-node-app:build',
|
buildTarget: 'my-node-app:build',
|
||||||
},
|
},
|
||||||
@ -75,14 +79,16 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(workspaceJson.projects['my-node-app'].architect.lint).toEqual({
|
expect(project.targets.lint).toEqual({
|
||||||
builder: '@nrwl/linter:eslint',
|
executor: '@nrwl/linter:eslint',
|
||||||
outputs: ['{options.outputFile}'],
|
outputs: ['{options.outputFile}'],
|
||||||
options: {
|
options: {
|
||||||
lintFilePatterns: ['apps/my-node-app/**/*.ts'],
|
lintFilePatterns: ['my-node-app/**/*.ts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(workspaceJson.projects['my-node-app-e2e']).toBeUndefined();
|
expect(() => readProjectConfiguration(tree, 'my-node-app-e2e')).toThrow(
|
||||||
|
/Cannot find/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update tags', async () => {
|
it('should update tags', async () => {
|
||||||
@ -104,13 +110,13 @@ describe('app', () => {
|
|||||||
name: 'myNodeApp',
|
name: 'myNodeApp',
|
||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
expect(tree.exists(`apps/my-node-app/jest.config.ts`)).toBeTruthy();
|
expect(tree.exists(`my-node-app/jest.config.ts`)).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-node-app/src/main.ts')).toBeTruthy();
|
expect(tree.exists('my-node-app/src/main.ts')).toBeTruthy();
|
||||||
|
|
||||||
const tsconfig = readJson(tree, 'apps/my-node-app/tsconfig.json');
|
const tsconfig = readJson(tree, 'my-node-app/tsconfig.json');
|
||||||
expect(tsconfig).toMatchInlineSnapshot(`
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"files": Array [],
|
"files": Array [],
|
||||||
"include": Array [],
|
"include": Array [],
|
||||||
"references": Array [
|
"references": Array [
|
||||||
@ -124,19 +130,19 @@ describe('app', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const tsconfigApp = readJson(tree, 'apps/my-node-app/tsconfig.app.json');
|
const tsconfigApp = readJson(tree, 'my-node-app/tsconfig.app.json');
|
||||||
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
expect(tsconfigApp.compilerOptions.outDir).toEqual('../dist/out-tsc');
|
||||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||||
expect(tsconfigApp.exclude).toEqual([
|
expect(tsconfigApp.exclude).toEqual([
|
||||||
'jest.config.ts',
|
'jest.config.ts',
|
||||||
'src/**/*.spec.ts',
|
'src/**/*.spec.ts',
|
||||||
'src/**/*.test.ts',
|
'src/**/*.test.ts',
|
||||||
]);
|
]);
|
||||||
const eslintrc = readJson(tree, 'apps/my-node-app/.eslintrc.json');
|
const eslintrc = readJson(tree, 'my-node-app/.eslintrc.json');
|
||||||
expect(eslintrc).toMatchInlineSnapshot(`
|
expect(eslintrc).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"extends": Array [
|
"extends": Array [
|
||||||
"../../.eslintrc.json",
|
"../.eslintrc.json",
|
||||||
],
|
],
|
||||||
"ignorePatterns": Array [
|
"ignorePatterns": Array [
|
||||||
"!**/*",
|
"!**/*",
|
||||||
@ -178,36 +184,33 @@ describe('app', () => {
|
|||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tsconfig = readJson(tree, 'apps/my-node-app/tsconfig.json');
|
const tsconfig = readJson(tree, 'my-node-app/tsconfig.json');
|
||||||
expect(tsconfig.extends).toBe('../../tsconfig.json');
|
expect(tsconfig.extends).toBe('../tsconfig.json');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update workspace.json', async () => {
|
it('should update project config', async () => {
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'myNodeApp',
|
name: 'myNodeApp',
|
||||||
directory: 'myDir',
|
directory: 'myDir',
|
||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
const workspaceJson = readJson(tree, '/workspace.json');
|
const project = readProjectConfiguration(tree, 'my-dir-my-node-app');
|
||||||
const nxJson = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-dir-my-node-app'].root).toEqual(
|
expect(project.root).toEqual('my-dir/my-node-app');
|
||||||
'apps/my-dir/my-node-app'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(project.targets.lint).toEqual({
|
||||||
workspaceJson.projects['my-dir-my-node-app'].architect.lint
|
executor: '@nrwl/linter:eslint',
|
||||||
).toEqual({
|
|
||||||
builder: '@nrwl/linter:eslint',
|
|
||||||
outputs: ['{options.outputFile}'],
|
outputs: ['{options.outputFile}'],
|
||||||
options: {
|
options: {
|
||||||
lintFilePatterns: ['apps/my-dir/my-node-app/**/*.ts'],
|
lintFilePatterns: ['my-dir/my-node-app/**/*.ts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-dir-my-node-app-e2e']).toBeUndefined();
|
expect(() =>
|
||||||
|
readProjectConfiguration(tree, 'my-dir-my-node-app-e2e')
|
||||||
|
).toThrow(/Cannot find/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update tags', async () => {
|
it('should update tags', async () => {
|
||||||
@ -239,8 +242,8 @@ describe('app', () => {
|
|||||||
|
|
||||||
// Make sure these exist
|
// Make sure these exist
|
||||||
[
|
[
|
||||||
`apps/my-dir/my-node-app/jest.config.ts`,
|
`my-dir/my-node-app/jest.config.ts`,
|
||||||
'apps/my-dir/my-node-app/src/main.ts',
|
'my-dir/my-node-app/src/main.ts',
|
||||||
].forEach((path) => {
|
].forEach((path) => {
|
||||||
expect(tree.exists(path)).toBeTruthy();
|
expect(tree.exists(path)).toBeTruthy();
|
||||||
});
|
});
|
||||||
@ -248,17 +251,17 @@ describe('app', () => {
|
|||||||
// Make sure these have properties
|
// Make sure these have properties
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
path: 'apps/my-dir/my-node-app/tsconfig.app.json',
|
path: 'my-dir/my-node-app/tsconfig.app.json',
|
||||||
lookupFn: (json) => json.compilerOptions.outDir,
|
lookupFn: (json) => json.compilerOptions.outDir,
|
||||||
expectedValue: '../../../dist/out-tsc',
|
expectedValue: '../../dist/out-tsc',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'apps/my-dir/my-node-app/tsconfig.app.json',
|
path: 'my-dir/my-node-app/tsconfig.app.json',
|
||||||
lookupFn: (json) => json.compilerOptions.types,
|
lookupFn: (json) => json.compilerOptions.types,
|
||||||
expectedValue: ['node'],
|
expectedValue: ['node'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'apps/my-dir/my-node-app/tsconfig.app.json',
|
path: 'my-dir/my-node-app/tsconfig.app.json',
|
||||||
lookupFn: (json) => json.exclude,
|
lookupFn: (json) => json.exclude,
|
||||||
expectedValue: [
|
expectedValue: [
|
||||||
'jest.config.ts',
|
'jest.config.ts',
|
||||||
@ -267,9 +270,9 @@ describe('app', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'apps/my-dir/my-node-app/.eslintrc.json',
|
path: 'my-dir/my-node-app/.eslintrc.json',
|
||||||
lookupFn: (json) => json.extends,
|
lookupFn: (json) => json.extends,
|
||||||
expectedValue: ['../../../.eslintrc.json'],
|
expectedValue: ['../../.eslintrc.json'],
|
||||||
},
|
},
|
||||||
].forEach(hasJsonValue);
|
].forEach(hasJsonValue);
|
||||||
});
|
});
|
||||||
@ -283,21 +286,18 @@ describe('app', () => {
|
|||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
expect(tree.exists('jest.config.ts')).toBeFalsy();
|
expect(tree.exists('jest.config.ts')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/src/test-setup.ts')).toBeFalsy();
|
expect(tree.exists('my-node-app/src/test-setup.ts')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/src/test.ts')).toBeFalsy();
|
expect(tree.exists('my-node-app/src/test.ts')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('my-node-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/jest.config.ts')).toBeFalsy();
|
expect(tree.exists('my-node-app/jest.config.ts')).toBeFalsy();
|
||||||
const workspaceJson = readJson(tree, 'workspace.json');
|
const project = readProjectConfiguration(tree, 'my-node-app');
|
||||||
expect(
|
expect(project.targets.test).toBeUndefined();
|
||||||
workspaceJson.projects['my-node-app'].architect.test
|
expect(project.targets.lint).toMatchInlineSnapshot(`
|
||||||
).toBeUndefined();
|
|
||||||
expect(workspaceJson.projects['my-node-app'].architect.lint)
|
|
||||||
.toMatchInlineSnapshot(`
|
|
||||||
Object {
|
Object {
|
||||||
"builder": "@nrwl/linter:eslint",
|
"executor": "@nrwl/linter:eslint",
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"lintFilePatterns": Array [
|
"lintFilePatterns": Array [
|
||||||
"apps/my-node-app/**/*.ts",
|
"my-node-app/**/*.ts",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"outputs": Array [
|
"outputs": Array [
|
||||||
@ -318,12 +318,10 @@ describe('app', () => {
|
|||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = readJson(tree, 'workspace.json').projects['my-frontend']
|
const project = readProjectConfiguration(tree, 'my-frontend');
|
||||||
.architect.serve;
|
const serve = project.targets.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual('my-frontend/proxy.conf.json');
|
||||||
'apps/my-frontend/proxy.conf.json'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should configure proxies for multiple node projects with the same frontend app', async () => {
|
it('should configure proxies for multiple node projects with the same frontend app', async () => {
|
||||||
@ -341,9 +339,9 @@ describe('app', () => {
|
|||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
|
|
||||||
expect(readJson(tree, 'apps/my-frontend/proxy.conf.json')).toEqual({
|
expect(readJson(tree, 'my-frontend/proxy.conf.json')).toEqual({
|
||||||
'/api': { target: 'http://localhost:3333', secure: false },
|
'/api': { target: 'http://localhost:3333', secure: false },
|
||||||
'/billing-api': { target: 'http://localhost:3333', secure: false },
|
'/billing-api': { target: 'http://localhost:3333', secure: false },
|
||||||
});
|
});
|
||||||
@ -358,12 +356,10 @@ describe('app', () => {
|
|||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = readJson(tree, 'workspace.json').projects['my-frontend']
|
const project = readProjectConfiguration(tree, 'my-frontend');
|
||||||
.architect.serve;
|
const serve = project.targets.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual('my-frontend/proxy.conf.json');
|
||||||
'apps/my-frontend/proxy.conf.json'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -375,18 +371,18 @@ describe('app', () => {
|
|||||||
babelJest: true,
|
babelJest: true,
|
||||||
} as Schema);
|
} as Schema);
|
||||||
|
|
||||||
expect(tree.read(`apps/my-node-app/jest.config.ts`, 'utf-8'))
|
expect(tree.read(`my-node-app/jest.config.ts`, 'utf-8'))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
"/* eslint-disable */
|
"/* eslint-disable */
|
||||||
export default {
|
export default {
|
||||||
displayName: 'my-node-app',
|
displayName: 'my-node-app',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../jest.preset.js',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\\\\\\\.[tj]s$': 'babel-jest'
|
'^.+\\\\\\\\.[tj]s$': 'babel-jest'
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
coverageDirectory: '../../coverage/apps/my-node-app'
|
coverageDirectory: '../coverage/my-node-app'
|
||||||
};
|
};
|
||||||
"
|
"
|
||||||
`);
|
`);
|
||||||
@ -399,15 +395,15 @@ describe('app', () => {
|
|||||||
js: true,
|
js: true,
|
||||||
} as Schema);
|
} as Schema);
|
||||||
|
|
||||||
expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy();
|
expect(tree.exists(`my-node-app/jest.config.js`)).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-node-app/src/main.js')).toBeTruthy();
|
expect(tree.exists('my-node-app/src/main.js')).toBeTruthy();
|
||||||
|
|
||||||
const tsConfig = readJson(tree, 'apps/my-node-app/tsconfig.json');
|
const tsConfig = readJson(tree, 'my-node-app/tsconfig.json');
|
||||||
expect(tsConfig.compilerOptions).toEqual({
|
expect(tsConfig.compilerOptions).toEqual({
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tsConfigApp = readJson(tree, 'apps/my-node-app/tsconfig.app.json');
|
const tsConfigApp = readJson(tree, 'my-node-app/tsconfig.app.json');
|
||||||
expect(tsConfigApp.include).toEqual(['src/**/*.ts', 'src/**/*.js']);
|
expect(tsConfigApp.include).toEqual(['src/**/*.ts', 'src/**/*.js']);
|
||||||
expect(tsConfigApp.exclude).toEqual([
|
expect(tsConfigApp.exclude).toEqual([
|
||||||
'jest.config.ts',
|
'jest.config.ts',
|
||||||
@ -418,16 +414,15 @@ describe('app', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update workspace.json', async () => {
|
it('should add project config', async () => {
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'myNodeApp',
|
name: 'myNodeApp',
|
||||||
js: true,
|
js: true,
|
||||||
} as Schema);
|
} as Schema);
|
||||||
const workspaceJson = readJson(tree, '/workspace.json');
|
const project = readProjectConfiguration(tree, 'my-node-app');
|
||||||
const project = workspaceJson.projects['my-node-app'];
|
const buildTarget = project.targets.build;
|
||||||
const buildTarget = project.architect.build;
|
|
||||||
|
|
||||||
expect(buildTarget.options.main).toEqual('apps/my-node-app/src/main.js');
|
expect(buildTarget.options.main).toEqual('my-node-app/src/main.js');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate js files for nested libs as well', async () => {
|
it('should generate js files for nested libs as well', async () => {
|
||||||
@ -436,10 +431,8 @@ describe('app', () => {
|
|||||||
directory: 'myDir',
|
directory: 'myDir',
|
||||||
js: true,
|
js: true,
|
||||||
} as Schema);
|
} as Schema);
|
||||||
expect(
|
expect(tree.exists(`my-dir/my-node-app/jest.config.js`)).toBeTruthy();
|
||||||
tree.exists(`apps/my-dir/my-node-app/jest.config.js`)
|
expect(tree.exists('my-dir/my-node-app/src/main.js')).toBeTruthy();
|
||||||
).toBeTruthy();
|
|
||||||
expect(tree.exists('apps/my-dir/my-node-app/src/main.js')).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,10 @@ function getWebpackBuildConfig(
|
|||||||
),
|
),
|
||||||
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
||||||
|
webpackConfig: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
'webpack.config.js'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
configurations: {
|
configurations: {
|
||||||
production: {
|
production: {
|
||||||
@ -151,6 +155,10 @@ function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (options.bundler !== 'webpack') {
|
||||||
|
tree.delete(joinPathFragments(options.appProjectRoot, 'webpack.config.js'));
|
||||||
|
}
|
||||||
|
|
||||||
if (options.framework) {
|
if (options.framework) {
|
||||||
generateFiles(
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
@ -358,11 +366,6 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
|
|
||||||
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
||||||
if (options.framework) {
|
|
||||||
options.bundler = options.bundler ?? 'esbuild';
|
|
||||||
} else {
|
|
||||||
options.bundler = 'webpack';
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
const { composePlugins, withNx} = require('@nrwl/webpack');
|
||||||
|
|
||||||
|
// Nx plugins for webpack.
|
||||||
|
module.exports = composePlugins(withNx(), (config) => {
|
||||||
|
// Update the webpack config as needed here.
|
||||||
|
// e.g. `config.plugins.push(new MyPlugin())`
|
||||||
|
return config;
|
||||||
|
});
|
||||||
@ -22,3 +22,4 @@ export { cypressComponentConfigGenerator } from './src/generators/cypress-compon
|
|||||||
export { componentTestGenerator } from './src/generators/component-test/component-test';
|
export { componentTestGenerator } from './src/generators/component-test/component-test';
|
||||||
export { setupTailwindGenerator } from './src/generators/setup-tailwind/setup-tailwind';
|
export { setupTailwindGenerator } from './src/generators/setup-tailwind/setup-tailwind';
|
||||||
export type { SupportedStyles } from './typings/style';
|
export type { SupportedStyles } from './typings/style';
|
||||||
|
export * from './plugins/with-react';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
ExecutorContext,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
logger,
|
logger,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
@ -15,7 +16,7 @@ import { gte } from 'semver';
|
|||||||
import { Configuration, DefinePlugin, WebpackPluginInstance } from 'webpack';
|
import { Configuration, DefinePlugin, WebpackPluginInstance } from 'webpack';
|
||||||
import * as mergeWebpack from 'webpack-merge';
|
import * as mergeWebpack from 'webpack-merge';
|
||||||
import { mergePlugins } from './merge-plugins';
|
import { mergePlugins } from './merge-plugins';
|
||||||
import { withReact } from '../webpack';
|
import { withReact } from '../with-react';
|
||||||
import { withNx, withWeb } from '@nrwl/webpack';
|
import { withNx, withWeb } from '@nrwl/webpack';
|
||||||
|
|
||||||
// This is shamelessly taken from CRA and modified for NX use
|
// This is shamelessly taken from CRA and modified for NX use
|
||||||
@ -128,7 +129,10 @@ export const webpack = async (
|
|||||||
withWeb(),
|
withWeb(),
|
||||||
withReact()
|
withReact()
|
||||||
);
|
);
|
||||||
const finalConfig = configure(baseWebpackConfig, { options: builderOptions });
|
const finalConfig = configure(baseWebpackConfig, {
|
||||||
|
options: builderOptions,
|
||||||
|
context: {} as ExecutorContext, // The context is not used here.
|
||||||
|
});
|
||||||
|
|
||||||
// Check whether the project .babelrc uses @emotion/babel-plugin. There's currently
|
// Check whether the project .babelrc uses @emotion/babel-plugin. There's currently
|
||||||
// a Storybook issue (https://github.com/storybookjs/storybook/issues/13277) which apparently
|
// a Storybook issue (https://github.com/storybookjs/storybook/issues/13277) which apparently
|
||||||
|
|||||||
@ -1,69 +1,4 @@
|
|||||||
import type { Configuration } from 'webpack';
|
import { withReact } from './with-react';
|
||||||
import ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
|
||||||
import { NormalizedWebpackExecutorOptions } from '@nrwl/webpack';
|
|
||||||
import { ExecutorContext } from 'nx/src/config/misc-interfaces';
|
|
||||||
|
|
||||||
// Add React-specific configuration
|
|
||||||
export function withReact() {
|
|
||||||
return function configure(
|
|
||||||
config: Configuration,
|
|
||||||
_ctx?: {
|
|
||||||
options: NormalizedWebpackExecutorOptions;
|
|
||||||
context: ExecutorContext;
|
|
||||||
}
|
|
||||||
): Configuration {
|
|
||||||
config.module.rules.push({
|
|
||||||
test: /\.svg$/,
|
|
||||||
issuer: /\.(js|ts|md)x?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: require.resolve('@svgr/webpack'),
|
|
||||||
options: {
|
|
||||||
svgo: false,
|
|
||||||
titleProp: true,
|
|
||||||
ref: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: require.resolve('file-loader'),
|
|
||||||
options: {
|
|
||||||
name: '[name].[hash].[ext]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (config.mode === 'development' && config['devServer']?.hot) {
|
|
||||||
// add `react-refresh/babel` to babel loader plugin
|
|
||||||
const babelLoader = config.module.rules.find(
|
|
||||||
(rule) =>
|
|
||||||
typeof rule !== 'string' &&
|
|
||||||
rule.loader?.toString().includes('babel-loader')
|
|
||||||
);
|
|
||||||
if (babelLoader && typeof babelLoader !== 'string') {
|
|
||||||
babelLoader.options['plugins'] = [
|
|
||||||
...(babelLoader.options['plugins'] || []),
|
|
||||||
[
|
|
||||||
require.resolve('react-refresh/babel'),
|
|
||||||
{
|
|
||||||
skipEnvCheck: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
// add https://github.com/pmmmwh/react-refresh-webpack-plugin to webpack plugin
|
|
||||||
config.plugins.push(new ReactRefreshPlugin());
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable webpack node api
|
|
||||||
config.node = {
|
|
||||||
__dirname: true,
|
|
||||||
__filename: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support existing default exports as well as new named export.
|
// Support existing default exports as well as new named export.
|
||||||
const legacyExport: any = withReact();
|
const legacyExport: any = withReact();
|
||||||
|
|||||||
69
packages/react/plugins/with-react.ts
Normal file
69
packages/react/plugins/with-react.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import type { Configuration } from 'webpack';
|
||||||
|
import { NormalizedWebpackExecutorOptions } from '@nrwl/webpack';
|
||||||
|
import { ExecutorContext } from 'nx/src/config/misc-interfaces';
|
||||||
|
|
||||||
|
const processed = new Set();
|
||||||
|
|
||||||
|
export function withReact() {
|
||||||
|
return function configure(
|
||||||
|
config: Configuration,
|
||||||
|
_ctx?: {
|
||||||
|
options: NormalizedWebpackExecutorOptions;
|
||||||
|
context: ExecutorContext;
|
||||||
|
}
|
||||||
|
): Configuration {
|
||||||
|
if (processed.has(config)) return config;
|
||||||
|
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.svg$/,
|
||||||
|
issuer: /\.(js|ts|md)x?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('@svgr/webpack'),
|
||||||
|
options: {
|
||||||
|
svgo: false,
|
||||||
|
titleProp: true,
|
||||||
|
ref: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve('file-loader'),
|
||||||
|
options: {
|
||||||
|
name: '[name].[hash].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (config.mode === 'development' && config['devServer']?.hot) {
|
||||||
|
// add `react-refresh/babel` to babel loader plugin
|
||||||
|
const babelLoader = config.module.rules.find(
|
||||||
|
(rule) =>
|
||||||
|
typeof rule !== 'string' &&
|
||||||
|
rule.loader?.toString().includes('babel-loader')
|
||||||
|
);
|
||||||
|
if (babelLoader && typeof babelLoader !== 'string') {
|
||||||
|
babelLoader.options['plugins'] = [
|
||||||
|
...(babelLoader.options['plugins'] || []),
|
||||||
|
[
|
||||||
|
require.resolve('react-refresh/babel'),
|
||||||
|
{
|
||||||
|
skipEnvCheck: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
config.plugins.push(new ReactRefreshPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable webpack node api
|
||||||
|
config.node = {
|
||||||
|
__dirname: true,
|
||||||
|
__filename: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
processed.add(config);
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -314,7 +314,7 @@ describe('app', () => {
|
|||||||
scripts: [],
|
scripts: [],
|
||||||
styles: ['apps/my-app/src/styles.css'],
|
styles: ['apps/my-app/src/styles.css'],
|
||||||
tsConfig: 'apps/my-app/tsconfig.app.json',
|
tsConfig: 'apps/my-app/tsconfig.app.json',
|
||||||
webpackConfig: '@nrwl/react/plugins/webpack',
|
webpackConfig: 'apps/my-app/webpack.config.js',
|
||||||
});
|
});
|
||||||
expect(targetConfig.build.configurations.production).toEqual({
|
expect(targetConfig.build.configurations.production).toEqual({
|
||||||
optimization: true,
|
optimization: true,
|
||||||
@ -792,7 +792,7 @@ describe('app', () => {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
workspaceJson.get('my-app').targets.build.options.webpackConfig
|
workspaceJson.get('my-app').targets.build.options.webpackConfig
|
||||||
).toEqual('@nrwl/react/plugins/webpack');
|
).toEqual('apps/my-app/webpack.config.js');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT add custom webpack config if bundler is vite', async () => {
|
it('should NOT add custom webpack config if bundler is vite', async () => {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,9 @@
|
|||||||
|
const { composePlugins, withNx } = require('@nrwl/webpack');
|
||||||
|
const { withReact } = require('@nrwl/react');
|
||||||
|
|
||||||
|
// Nx plugins for webpack.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), (config) => {
|
||||||
|
// Update the webpack config as needed here.
|
||||||
|
// e.g. `config.plugins.push(new MyPlugin())`
|
||||||
|
return config;
|
||||||
|
});
|
||||||
@ -72,7 +72,10 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
scripts: [],
|
scripts: [],
|
||||||
webpackConfig: '@nrwl/react/plugins/webpack',
|
webpackConfig: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
'webpack.config.js'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
configurations: {
|
configurations: {
|
||||||
development: {
|
development: {
|
||||||
|
|||||||
@ -9,15 +9,15 @@ import { getAppTests } from './get-app-tests';
|
|||||||
export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||||
let styleSolutionSpecificAppFiles: string;
|
let styleSolutionSpecificAppFiles: string;
|
||||||
if (options.styledModule && options.style !== 'styled-jsx') {
|
if (options.styledModule && options.style !== 'styled-jsx') {
|
||||||
styleSolutionSpecificAppFiles = '../files/styled-module';
|
styleSolutionSpecificAppFiles = '../files/style-styled-module';
|
||||||
} else if (options.style === 'styled-jsx') {
|
} else if (options.style === 'styled-jsx') {
|
||||||
styleSolutionSpecificAppFiles = '../files/styled-jsx';
|
styleSolutionSpecificAppFiles = '../files/style-styled-jsx';
|
||||||
} else if (options.style === 'none') {
|
} else if (options.style === 'none') {
|
||||||
styleSolutionSpecificAppFiles = '../files/none';
|
styleSolutionSpecificAppFiles = '../files/style-none';
|
||||||
} else if (options.globalCss) {
|
} else if (options.globalCss) {
|
||||||
styleSolutionSpecificAppFiles = '../files/global-css';
|
styleSolutionSpecificAppFiles = '../files/style-global-css';
|
||||||
} else {
|
} else {
|
||||||
styleSolutionSpecificAppFiles = '../files/css-module';
|
styleSolutionSpecificAppFiles = '../files/style-css-module';
|
||||||
}
|
}
|
||||||
|
|
||||||
const relativePathToRootTsConfig = getRelativePathToRootTsConfig(
|
const relativePathToRootTsConfig = getRelativePathToRootTsConfig(
|
||||||
@ -38,7 +38,9 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
host,
|
host,
|
||||||
join(
|
join(
|
||||||
__dirname,
|
__dirname,
|
||||||
options.bundler === 'vite' ? '../files/common-vite' : '../files/common'
|
options.bundler === 'vite'
|
||||||
|
? '../files/base-vite'
|
||||||
|
: '../files/base-webpack'
|
||||||
),
|
),
|
||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
templateVariables
|
templateVariables
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
const { withModuleFederationForSSR } = require('@nrwl/react/module-federation');
|
import { composePlugins, withNx } from '@nrwl/webpack';
|
||||||
const baseConfig = require("./module-federation.server.config");
|
import { withReact } from '@nrwl/react';
|
||||||
|
import { withModuleFederationForSSR } from '@nrwl/react/module-federation';
|
||||||
|
|
||||||
|
const baseConfig = require('./module-federation.config');
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
...baseConfig
|
...baseConfig
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withModuleFederationForSSR(defaultConfig);
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederationForSSR(defaultConfig));
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
// @ts-check
|
module.exports = {
|
||||||
|
name: '<%= projectName %>',
|
||||||
/**
|
remotes: [
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
<% remotes.forEach(function(r) {%> "<%= r.fileName %>", <% }); %>
|
||||||
**/
|
],
|
||||||
const moduleFederationConfig = {
|
|
||||||
name: '<%= projectName %>',
|
|
||||||
remotes: [
|
|
||||||
<% remotes.forEach(function(r) {%> "<%= r.fileName %>", <% }); %>
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = moduleFederationConfig;
|
|
||||||
@ -1,13 +1,12 @@
|
|||||||
// @ts-check
|
const { composePlugins, withNx } = require('@nrwl/webpack');
|
||||||
|
const { withReact } = require('@nrwl/react');
|
||||||
const { withModuleFederation } = require('@nrwl/react/module-federation');
|
const { withModuleFederation } = require('@nrwl/react/module-federation');
|
||||||
|
|
||||||
const baseConfig = require('./module-federation.config');
|
const baseConfig = require('./module-federation.config');
|
||||||
|
|
||||||
/**
|
const config = {
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
...baseConfig,
|
||||||
**/
|
|
||||||
const defaultConfig = {
|
|
||||||
...baseConfig,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withModuleFederation(defaultConfig);
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config));
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
// @ts-check
|
const { composePlugins, withNx } = require('@nrwl/webpack');
|
||||||
|
const { withReact } = require('@nrwl/react');
|
||||||
|
const { withModuleFederation } = require('@nrwl/react/module-federation'));
|
||||||
|
|
||||||
const { withModuleFederation } = require('@nrwl/react/module-federation');
|
|
||||||
const baseConfig = require('./module-federation.config');
|
const baseConfig = require('./module-federation.config');
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
|
||||||
**/
|
|
||||||
const prodConfig = {
|
const prodConfig = {
|
||||||
...baseConfig,
|
...baseConfig,
|
||||||
/*
|
/*
|
||||||
@ -30,4 +28,5 @@ const prodConfig = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withModuleFederation(prodConfig);
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(prodConfig));
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
// @ts-check
|
module.exports = {
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
|
||||||
**/
|
|
||||||
const moduleFederationConfig = {
|
|
||||||
name: '<%= projectName %>',
|
name: '<%= projectName %>',
|
||||||
exposes: {
|
exposes: {
|
||||||
'./Module': '<%= appProjectRoot %>/src/remote-entry.ts',
|
'./Module': '<%= appProjectRoot %>/src/remote-entry.ts',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = moduleFederationConfig;
|
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
const { composePlugins, withNx } = require('@nrwl/webpack');
|
||||||
|
const { withReact } = require('@nrwl/react');
|
||||||
const { withModuleFederationForSSR } = require('@nrwl/react/module-federation');
|
const { withModuleFederationForSSR } = require('@nrwl/react/module-federation');
|
||||||
|
|
||||||
const baseConfig = require("./module-federation.server.config");
|
const baseConfig = require("./module-federation.server.config");
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
...baseConfig
|
...baseConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withModuleFederationForSSR(defaultConfig);
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederationForSSR(defaultConfig));
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
// @ts-check
|
module.exports = {
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
|
||||||
**/
|
|
||||||
const moduleFederationConfig = {
|
|
||||||
name: '<%= projectName %>',
|
name: '<%= projectName %>',
|
||||||
exposes: {
|
exposes: {
|
||||||
'./Module': './src/remote-entry.ts',
|
'./Module': './src/remote-entry.ts',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = moduleFederationConfig;
|
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
// @ts-check
|
const { composePlugins, withNx } = require('@nrwl/webpack');
|
||||||
|
const { withReact } = require('@nrwl/react');
|
||||||
|
const { withModuleFederation } = require('@nrwl/react/module-federation'));
|
||||||
|
|
||||||
const { withModuleFederation } = require('@nrwl/react/module-federation');
|
|
||||||
const baseConfig = require('./module-federation.config');
|
const baseConfig = require('./module-federation.config');
|
||||||
|
|
||||||
/**
|
const config = {
|
||||||
* @type {import('@nrwl/devkit').ModuleFederationConfig}
|
...baseConfig,
|
||||||
**/
|
|
||||||
const defaultConfig = {
|
|
||||||
...baseConfig,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withModuleFederation(defaultConfig);
|
// Nx plugins for webpack to build config object from Nx options and context.
|
||||||
|
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config));
|
||||||
|
|||||||
@ -107,7 +107,7 @@ export async function setupSsrGenerator(tree: Tree, options: Schema) {
|
|||||||
compiler: 'babel',
|
compiler: 'babel',
|
||||||
externalDependencies: 'all',
|
externalDependencies: 'all',
|
||||||
outputHashing: 'none',
|
outputHashing: 'none',
|
||||||
webpackConfig: '@nrwl/react/plugins/webpack',
|
webpackConfig: joinPathFragments(projectRoot, 'webpack.config.js'),
|
||||||
},
|
},
|
||||||
configurations: {
|
configurations: {
|
||||||
development: {
|
development: {
|
||||||
|
|||||||
@ -351,6 +351,7 @@ describe('app', () => {
|
|||||||
scripts: [],
|
scripts: [],
|
||||||
styles: ['apps/my-app/src/styles.css'],
|
styles: ['apps/my-app/src/styles.css'],
|
||||||
tsConfig: 'apps/my-app/tsconfig.app.json',
|
tsConfig: 'apps/my-app/tsconfig.app.json',
|
||||||
|
webpackConfig: 'apps/my-app/webpack.config.js',
|
||||||
});
|
});
|
||||||
expect(architectConfig.build.configurations.production).toEqual({
|
expect(architectConfig.build.configurations.production).toEqual({
|
||||||
optimization: true,
|
optimization: true,
|
||||||
|
|||||||
@ -44,7 +44,7 @@ function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
tree,
|
tree,
|
||||||
join(
|
join(
|
||||||
__dirname,
|
__dirname,
|
||||||
options.bundler === 'vite' ? './files/app-vite' : './files/app'
|
options.bundler === 'vite' ? './files/app-vite' : './files/app-webpack'
|
||||||
),
|
),
|
||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
{
|
{
|
||||||
@ -81,6 +81,10 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
|||||||
tsConfig,
|
tsConfig,
|
||||||
compiler: options.compiler ?? 'babel',
|
compiler: options.compiler ?? 'babel',
|
||||||
devServer: true,
|
devServer: true,
|
||||||
|
webpackConfig: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
'webpack.config.js'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
const project = readProjectConfiguration(tree, options.projectName);
|
const project = readProjectConfiguration(tree, options.projectName);
|
||||||
const prodConfig = project.targets.build.configurations.production;
|
const prodConfig = project.targets.build.configurations.production;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,8 @@
|
|||||||
|
const { composePlugins, withNx, withWeb } = require('@nrwl/webpack');
|
||||||
|
|
||||||
|
// Nx plugins for webpack.
|
||||||
|
module.exports = composePlugins(withNx(), withWeb(), (config) => {
|
||||||
|
// Update the webpack config as needed here.
|
||||||
|
// e.g. `config.plugins.push(new MyPlugin())`
|
||||||
|
return config;
|
||||||
|
});
|
||||||
@ -1,13 +0,0 @@
|
|||||||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
|
||||||
# For additional information regarding the format and rule options, please see:
|
|
||||||
# https://github.com/browserslist/browserslist#queries
|
|
||||||
#
|
|
||||||
# If you need to support different browsers in production, you may tweak the list below.
|
|
||||||
|
|
||||||
last 1 Chrome version
|
|
||||||
last 1 Firefox version
|
|
||||||
last 2 Edge major versions
|
|
||||||
last 2 Safari major version
|
|
||||||
last 2 iOS major versions
|
|
||||||
Firefox ESR
|
|
||||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|
||||||
@ -56,7 +56,7 @@ export async function* devServerExecutor(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let webpackConfig = getDevServerConfig(context, buildOptions, serveOptions);
|
let config = getDevServerConfig(context, buildOptions, serveOptions);
|
||||||
|
|
||||||
if (buildOptions.webpackConfig) {
|
if (buildOptions.webpackConfig) {
|
||||||
let customWebpack = resolveCustomWebpackConfig(
|
let customWebpack = resolveCustomWebpackConfig(
|
||||||
@ -68,16 +68,17 @@ export async function* devServerExecutor(
|
|||||||
customWebpack = await customWebpack;
|
customWebpack = await customWebpack;
|
||||||
}
|
}
|
||||||
|
|
||||||
webpackConfig = await customWebpack(webpackConfig, {
|
config = await customWebpack(config, {
|
||||||
buildOptions,
|
options: buildOptions,
|
||||||
|
context,
|
||||||
configuration: serveOptions.buildTarget.split(':')[2],
|
configuration: serveOptions.buildTarget.split(':')[2],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return yield* eachValueFrom(
|
return yield* eachValueFrom(
|
||||||
runWebpackDevServer(webpackConfig, webpack, WebpackDevServer).pipe(
|
runWebpackDevServer(config, webpack, WebpackDevServer).pipe(
|
||||||
tap(({ stats }) => {
|
tap(({ stats }) => {
|
||||||
console.info(stats.toString((webpackConfig as any).stats));
|
console.info(stats.toString((config as any).stats));
|
||||||
}),
|
}),
|
||||||
map(({ baseUrl, stats }) => {
|
map(({ baseUrl, stats }) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -83,6 +83,7 @@ export interface WebpackExecutorOptions {
|
|||||||
|
|
||||||
export interface NormalizedWebpackExecutorOptions
|
export interface NormalizedWebpackExecutorOptions
|
||||||
extends WebpackExecutorOptions {
|
extends WebpackExecutorOptions {
|
||||||
|
outputFileName: string;
|
||||||
assets?: AssetGlobPattern[];
|
assets?: AssetGlobPattern[];
|
||||||
root?: string;
|
root?: string;
|
||||||
projectRoot?: string;
|
projectRoot?: string;
|
||||||
|
|||||||
@ -1,37 +1,35 @@
|
|||||||
import { type Compiler, sources, type WebpackPluginInstance } from 'webpack';
|
import { type Compiler, sources, type WebpackPluginInstance } from 'webpack';
|
||||||
import {
|
import {
|
||||||
|
createLockFile,
|
||||||
|
createPackageJson,
|
||||||
ExecutorContext,
|
ExecutorContext,
|
||||||
type ProjectGraph,
|
type ProjectGraph,
|
||||||
serializeJson,
|
serializeJson,
|
||||||
createPackageJson,
|
|
||||||
createLockFile,
|
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import {
|
import {
|
||||||
getHelperDependenciesFromProjectGraph,
|
getHelperDependenciesFromProjectGraph,
|
||||||
HelperDependency,
|
HelperDependency,
|
||||||
} from '@nrwl/js/src/utils/compiler-helper-dependency';
|
} from '@nrwl/js/src/utils/compiler-helper-dependency';
|
||||||
import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
|
|
||||||
import { NormalizedWebpackExecutorOptions } from '../executors/webpack/schema';
|
|
||||||
import { getLockFileName } from 'nx/src/lock-file/lock-file';
|
import { getLockFileName } from 'nx/src/lock-file/lock-file';
|
||||||
|
|
||||||
export class GeneratePackageJsonWebpackPlugin implements WebpackPluginInstance {
|
const pluginName = 'GeneratePackageJsonPlugin';
|
||||||
|
|
||||||
|
export class GeneratePackageJsonPlugin implements WebpackPluginInstance {
|
||||||
private readonly projectGraph: ProjectGraph;
|
private readonly projectGraph: ProjectGraph;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly context: ExecutorContext,
|
private readonly options: { tsConfig: string; outputFileName: string },
|
||||||
private readonly options: NormalizedWebpackExecutorOptions
|
private readonly context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
this.projectGraph = context.projectGraph;
|
this.projectGraph = context.projectGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(compiler: Compiler): void {
|
apply(compiler: Compiler): void {
|
||||||
const pluginName = this.constructor.name;
|
|
||||||
|
|
||||||
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
|
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
|
||||||
compilation.hooks.processAssets.tap(
|
compilation.hooks.processAssets.tap(
|
||||||
{
|
{
|
||||||
name: 'nx-generate-package-json-plugin',
|
name: pluginName,
|
||||||
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@ -17,18 +17,18 @@ export function getBaseWebpackPartial(
|
|||||||
|
|
||||||
export type NxWebpackPlugin = (
|
export type NxWebpackPlugin = (
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
ctx?: {
|
ctx: {
|
||||||
options: NormalizedWebpackExecutorOptions;
|
options: NormalizedWebpackExecutorOptions;
|
||||||
context?: ExecutorContext;
|
context: ExecutorContext;
|
||||||
}
|
}
|
||||||
) => Configuration;
|
) => Configuration;
|
||||||
|
|
||||||
export function composePlugins(...plugins: NxWebpackPlugin[]) {
|
export function composePlugins(...plugins: NxWebpackPlugin[]) {
|
||||||
return function combined(
|
return function combined(
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
ctx?: {
|
ctx: {
|
||||||
options: NormalizedWebpackExecutorOptions;
|
options: NormalizedWebpackExecutorOptions;
|
||||||
context?: ExecutorContext;
|
context: ExecutorContext;
|
||||||
}
|
}
|
||||||
): Configuration {
|
): Configuration {
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
export function tsNodeRegister(file: string = '', tsConfig?: string) {
|
export function tsNodeRegister(file: string = '', tsConfig?: string) {
|
||||||
if (!file?.endsWith('.ts')) return;
|
if (!file?.endsWith('.ts')) return;
|
||||||
|
|
||||||
|
// Avoid double-registering which can lead to issues type-checking already transformed files.
|
||||||
|
if (isRegistered()) return;
|
||||||
|
|
||||||
// Register TS compiler lazily
|
// Register TS compiler lazily
|
||||||
require('ts-node').register({
|
require('ts-node').register({
|
||||||
project: tsConfig,
|
project: tsConfig,
|
||||||
@ -29,3 +33,9 @@ export function resolveCustomWebpackConfig(path: string, tsConfig: string) {
|
|||||||
// `{ default: { ... } }`
|
// `{ default: { ... } }`
|
||||||
return customWebpackConfig.default || customWebpackConfig;
|
return customWebpackConfig.default || customWebpackConfig;
|
||||||
}
|
}
|
||||||
|
export function isRegistered() {
|
||||||
|
return (
|
||||||
|
require.extensions['.ts'] != undefined ||
|
||||||
|
require.extensions['.tsx'] != undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
|||||||
import { NormalizedWebpackExecutorOptions } from '../executors/webpack/schema';
|
import { NormalizedWebpackExecutorOptions } from '../executors/webpack/schema';
|
||||||
import { StatsJsonPlugin } from '../plugins/stats-json-plugin';
|
import { StatsJsonPlugin } from '../plugins/stats-json-plugin';
|
||||||
import { createCopyPlugin } from './create-copy-plugin';
|
import { createCopyPlugin } from './create-copy-plugin';
|
||||||
import { GeneratePackageJsonWebpackPlugin } from '../plugins/generate-package-json-webpack-plugin';
|
import { GeneratePackageJsonPlugin } from '../plugins/generate-package-json-plugin';
|
||||||
import { getOutputHashFormat } from './hash-format';
|
import { getOutputHashFormat } from './hash-format';
|
||||||
|
|
||||||
const IGNORED_WEBPACK_WARNINGS = [
|
const IGNORED_WEBPACK_WARNINGS = [
|
||||||
@ -22,6 +22,8 @@ const IGNORED_WEBPACK_WARNINGS = [
|
|||||||
const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx'];
|
const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx'];
|
||||||
const mainFields = ['main', 'module'];
|
const mainFields = ['main', 'module'];
|
||||||
|
|
||||||
|
const processed = new Set();
|
||||||
|
|
||||||
export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
||||||
return function configure(
|
return function configure(
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
@ -33,7 +35,10 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
context: ExecutorContext;
|
context: ExecutorContext;
|
||||||
}
|
}
|
||||||
): Configuration {
|
): Configuration {
|
||||||
|
if (processed.has(config)) return config;
|
||||||
|
|
||||||
const plugins: WebpackPluginInstance[] = [];
|
const plugins: WebpackPluginInstance[] = [];
|
||||||
|
|
||||||
if (!opts?.skipTypeChecking) {
|
if (!opts?.skipTypeChecking) {
|
||||||
plugins.push(
|
plugins.push(
|
||||||
new ForkTsCheckerWebpackPlugin({
|
new ForkTsCheckerWebpackPlugin({
|
||||||
@ -88,7 +93,7 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.generatePackageJson && context) {
|
if (options.generatePackageJson && context) {
|
||||||
plugins.push(new GeneratePackageJsonWebpackPlugin(context, options));
|
plugins.push(new GeneratePackageJsonPlugin(options, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.statsJson) {
|
if (options.statsJson) {
|
||||||
@ -118,7 +123,7 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
? `[name]${hashFormat.chunk}.js`
|
? `[name]${hashFormat.chunk}.js`
|
||||||
: '[name].js';
|
: '[name].js';
|
||||||
|
|
||||||
return {
|
const updated = {
|
||||||
...config,
|
...config,
|
||||||
target: options.target,
|
target: options.target,
|
||||||
node: false as const,
|
node: false as const,
|
||||||
@ -132,14 +137,14 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
mode:
|
mode:
|
||||||
process.env.NODE_ENV === 'development' ||
|
process.env.NODE_ENV === 'development' ||
|
||||||
process.env.NODE_ENV === 'production'
|
process.env.NODE_ENV === 'production'
|
||||||
? process.env.NODE_ENV
|
? (process.env.NODE_ENV as 'development' | 'production')
|
||||||
: 'none',
|
: ('none' as const),
|
||||||
devtool:
|
devtool:
|
||||||
options.sourceMap === 'hidden'
|
options.sourceMap === 'hidden'
|
||||||
? 'hidden-source-map'
|
? 'hidden-source-map'
|
||||||
: options.sourceMap
|
: options.sourceMap
|
||||||
? 'source-map'
|
? 'source-map'
|
||||||
: false,
|
: (false as const),
|
||||||
entry,
|
entry,
|
||||||
output: {
|
output: {
|
||||||
...config.output,
|
...config.output,
|
||||||
@ -150,7 +155,7 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
hashFunction: 'xxhash64',
|
hashFunction: 'xxhash64',
|
||||||
// Disabled for performance
|
// Disabled for performance
|
||||||
pathinfo: false,
|
pathinfo: false,
|
||||||
scriptType: 'module',
|
scriptType: 'module' as const,
|
||||||
},
|
},
|
||||||
watch: options.watch,
|
watch: options.watch,
|
||||||
watchOptions: {
|
watchOptions: {
|
||||||
@ -186,6 +191,7 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
? new TerserPlugin({
|
? new TerserPlugin({
|
||||||
parallel: true,
|
parallel: true,
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
|
keep_classnames: true,
|
||||||
ecma: 2020,
|
ecma: 2020,
|
||||||
safari10: true,
|
safari10: true,
|
||||||
output: {
|
output: {
|
||||||
@ -208,7 +214,7 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
},
|
},
|
||||||
performance: {
|
performance: {
|
||||||
...config.performance,
|
...config.performance,
|
||||||
hints: false,
|
hints: false as const,
|
||||||
},
|
},
|
||||||
experiments: { ...config.experiments, cacheUnaffected: true },
|
experiments: { ...config.experiments, cacheUnaffected: true },
|
||||||
ignoreWarnings: [
|
ignoreWarnings: [
|
||||||
@ -269,6 +275,9 @@ export function withNx(opts?: { skipTypeChecking?: boolean }) {
|
|||||||
usedExports: !!options.verbose,
|
usedExports: !!options.verbose,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
processed.add(updated);
|
||||||
|
return updated;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from 'webpack';
|
} from 'webpack';
|
||||||
import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
|
import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { basename } from 'path';
|
||||||
import { getOutputHashFormat } from '@nrwl/webpack/src/utils/hash-format';
|
import { getOutputHashFormat } from '@nrwl/webpack/src/utils/hash-format';
|
||||||
import { PostcssCliResources } from '@nrwl/webpack/src/utils/webpack/plugins/postcss-cli-resources';
|
import { PostcssCliResources } from '@nrwl/webpack/src/utils/webpack/plugins/postcss-cli-resources';
|
||||||
import { normalizeExtraEntryPoints } from '@nrwl/webpack/src/utils/webpack/normalize-entry';
|
import { normalizeExtraEntryPoints } from '@nrwl/webpack/src/utils/webpack/normalize-entry';
|
||||||
@ -19,7 +20,6 @@ import CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|||||||
import MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
import MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
import autoprefixer = require('autoprefixer');
|
import autoprefixer = require('autoprefixer');
|
||||||
import postcssImports = require('postcss-import');
|
import postcssImports = require('postcss-import');
|
||||||
import { basename } from 'path';
|
|
||||||
|
|
||||||
interface PostcssOptions {
|
interface PostcssOptions {
|
||||||
(loader: any): any;
|
(loader: any): any;
|
||||||
@ -27,11 +27,15 @@ interface PostcssOptions {
|
|||||||
config?: string;
|
config?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const processed = new Set();
|
||||||
|
|
||||||
export function withWeb() {
|
export function withWeb() {
|
||||||
return function configure(
|
return function configure(
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
{ options }: { options: NormalizedWebpackExecutorOptions }
|
{ options }: { options: NormalizedWebpackExecutorOptions }
|
||||||
): Configuration {
|
): Configuration {
|
||||||
|
if (processed.has(config)) return config;
|
||||||
|
|
||||||
const plugins = [];
|
const plugins = [];
|
||||||
|
|
||||||
const stylesOptimization =
|
const stylesOptimization =
|
||||||
@ -246,9 +250,6 @@ export function withWeb() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// context needs to be set for babel to pick up correct babelrc
|
|
||||||
config.context = path.join(options.root, options.projectRoot);
|
|
||||||
|
|
||||||
config.output = {
|
config.output = {
|
||||||
...config.output,
|
...config.output,
|
||||||
crossOriginLoading: options.subresourceIntegrity
|
crossOriginLoading: options.subresourceIntegrity
|
||||||
@ -303,7 +304,7 @@ export function withWeb() {
|
|||||||
config.module = {
|
config.module = {
|
||||||
...config.module,
|
...config.module,
|
||||||
rules: [
|
rules: [
|
||||||
...config.module.rules,
|
...(config.module.rules ?? []),
|
||||||
...rules,
|
...rules,
|
||||||
{
|
{
|
||||||
test: /\.(bmp|png|jpe?g|gif|webp|avif)$/,
|
test: /\.(bmp|png|jpe?g|gif|webp|avif)$/,
|
||||||
@ -323,6 +324,7 @@ export function withWeb() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
processed.add(config);
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user