Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dev-server): add managed paths #7713

Merged
merged 29 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
297a656
find & add the managed paths of the workspace
leimonio Jul 28, 2023
3c636af
log errors from webpack & webpack dev server
leimonio Jul 28, 2023
dbf42ce
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Jul 28, 2023
477b576
update naming & chnage to private member
leimonio Jul 31, 2023
5b204d4
register on component add and remove
leimonio Jul 31, 2023
354b008
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Jul 31, 2023
564c8ab
update & use of packages excluder component
leimonio Aug 3, 2023
4b354dc
rename format to target
leimonio Aug 3, 2023
5191b2e
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 3, 2023
657307a
fix linting
leimonio Aug 3, 2023
233883b
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 3, 2023
2b1191f
Merge branch 'master' into feat/add-managed-paths
GiladShoham Aug 8, 2023
75c8a52
fix buil compilation issue
leimonio Aug 8, 2023
f902f60
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 8, 2023
86b00eb
Merge branch 'master' into feat/add-managed-paths
leimonio Aug 10, 2023
aad877d
update composition & docs
leimonio Aug 10, 2023
db37996
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 10, 2023
98c3a50
Merge branch 'master' into feat/add-managed-paths
leimonio Aug 11, 2023
ef833df
Merge branch 'master' into feat/add-managed-paths
GiladShoham Aug 14, 2023
887b799
Merge branch 'master' into feat/add-managed-paths
GiladShoham Aug 14, 2023
7316a0f
Merge branch 'master' into feat/add-managed-paths
leimonio Aug 15, 2023
8fb073a
Merge branch 'master' into feat/add-managed-paths
GiladShoham Aug 17, 2023
29dc2c8
move set component paths regexs to happen on pre start slot
GiladShoham Aug 17, 2023
8df9255
Merge branch 'master' into feat/add-managed-paths
GiladShoham Aug 17, 2023
bf671e4
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 17, 2023
f0782bb
fix with defaults
leimonio Aug 17, 2023
629b082
Merge branch 'master' of github.com:teambit/bit into feat/add-managed…
leimonio Aug 17, 2023
b252c53
Merge branch 'master' into feat/add-managed-paths
leimonio Aug 18, 2023
99a3ce0
Merge branch 'master' into feat/add-managed-paths
leimonio Aug 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions scopes/compilation/bundler/dev-server.service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ export class DevServerService implements EnvService<ComponentServer, DevServerDe
name = 'dev server';

constructor(
/**
* browser runtime slot
*/
private pubsub: PubsubMain,

private dependencyResolver: DependencyResolverMain,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
type generateNodeModulesPatternOptions = {
export enum PatternTarget {
/**
* Used in Jest `transformIgnorePatterns` options
*/
JEST = 'jest',
/**
* Used in Webpack `snapshot.managedPaths` options
*/
WEBPACK = 'webpack',
}

type GenerateNodeModulesPatternOptions<T> = {
/**
* An array of packages name to exclude in the regex.
*/
Expand All @@ -8,30 +19,62 @@ type generateNodeModulesPatternOptions = {
* A component package looks like `@org/scope.namespace.component-name`.
*/
excludeComponents?: boolean;
/**
* The format to return the patterns.
*/
format?: T;
};

const patternTargetMap = {
[PatternTarget.JEST]: toJestPattern,
[PatternTarget.WEBPACK]: toWebpackPattern,
};

type PatternTargetMap = typeof patternTargetMap;
type PatternReturnType<T extends PatternTarget> = ReturnType<PatternTargetMap[T]>;

/**
* A function that receives an array of packages names and returns a pattern (string) of a regex that matches any node_modules/package-name except the provided package-names.
* @param {string[]} packages - array of packages.
* @returns {string} node modules catched packages regex.
*/
export function generateNodeModulesPattern({
packages = [],
excludeComponents,
}: generateNodeModulesPatternOptions): string {
const negativeLookaheadPatterns = packages.reduce((acc: string[], curr) => {
const yarnPattern = curr;
const pnpmCurr = curr.replace(/\//g, '\\+');
const pnpmPattern = `\\.pnpm/(.*[+/])?${pnpmCurr}.*`;
export function generateNodeModulesPattern<T extends PatternTarget>(
options: GenerateNodeModulesPatternOptions<T>
): PatternReturnType<T> {
const { packages = [], excludeComponents, format = PatternTarget.JEST } = options;
const negativeLookaheadPatterns = packages.reduce((acc: string[], packageName) => {
const yarnPattern = packageName.replace(/\//g, '[\\/]');
const pnpmPackageName = packageName.replace(/\//g, '\\+');
const pnpmPattern = `\\.pnpm[\\/](.*[+\\/])?${pnpmPackageName}.*`;
return [...acc, yarnPattern, pnpmPattern];
}, []);

if (excludeComponents) {
negativeLookaheadPatterns.push(
'@[^/]+/([^/]+\\.)+[^/]+',
'\\.pnpm/(.+[+/])?@[^+]+\\+([^+]+\\.)+[^+]+',
'\\.pnpm/.+/node_modules/@[^/]+/([^/]+\\.)+[^/]+'
);
}
const transformIgnorePattern = `node_modules/(?!(${negativeLookaheadPatterns.join('|')})/)`;
return transformIgnorePattern;

return patternTargetMap[format](negativeLookaheadPatterns) as PatternReturnType<T>;
}

function toJestPattern(patterns: string[]) {
return `node_modules/(?!(${patterns.join('|')})/)`;
}

/**
* Webpack managed paths evaluate absolutes paths to `package.json` files.
* We need to generate a pattern that excludes the `package.json` files of the bit component packages.
* Example:
* - Component package: `@my-org/my-scope.components`
* - Webpack path: `/Users/aUser/dev/bit-example/node_modules/@my-org/my-scope.components/package.json`
* - RegExp to exclude this path from managed paths: `/^(.+?[\\/]node_modules[\\/](?!(@my-org[\\/]my-scope.components))(@.+?[\\/])?.+?)[\\/]/`
*/

function toWebpackPattern(patterns: string[]) {
return patterns.map((pattern) => {
return `^(.+?[\\/]node_modules[\\/](?!(${pattern}))(@.+?[\\/])?.+?)[\\/]`;
});
}
2 changes: 1 addition & 1 deletion scopes/dependencies/modules/packages-excluder/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { generateNodeModulesPattern } from './generate-node-modules-pattern';
export { generateNodeModulesPattern, PatternTarget } from './generate-node-modules-pattern';
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function RegexExample() {
const [regexResult, setRegexResult] = useState(true);

useEffect(() => {
const pattern = generateNodeModulesPattern({ packages: packagesToExclude.split(','), excludeComponents });
const pattern = generateNodeModulesPattern({ packages: packagesToExclude.split(','), excludeComponents }) as string;
setCalculatedRegex(pattern);
const regex = new RegExp(pattern);
setRegexResult(regex.test(`node_modules/${packageToCheck}/some-path`));
Expand Down
5 changes: 3 additions & 2 deletions scopes/harmony/application/build-application.task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ export class AppsBuildTask implements BuildTask {
appResult.componentResult.warnings || []
);
// @ts-ignore
merged.componentResult._metadata.buildDeployContexts = // @ts-ignore
(merged.componentResult._metadata.buildDeployContexts || [])
merged.componentResult._metadata.buildDeployContexts = ( // @ts-ignore
merged.componentResult._metadata.buildDeployContexts || []
)
// @ts-ignore
.concat(appResult.componentResult._metadata || []);
});
Expand Down
7 changes: 7 additions & 0 deletions scopes/webpack/webpack/config/webpack.dev.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function configFactory(
entryFiles: string[],
publicRoot: string,
publicPath: string,
componentPathsRegExps: RegExp[],
pubsub: PubsubMain,
title?: string,
favicon?: string
Expand Down Expand Up @@ -72,6 +73,7 @@ export function configFactory(

stats: {
errorDetails: true,
logging: 'error',
},

devServer: {
Expand Down Expand Up @@ -107,6 +109,7 @@ export function configFactory(

client: {
overlay: false,
logging: 'error',
},

setupMiddlewares: (middlewares, devServer) => {
Expand Down Expand Up @@ -160,6 +163,10 @@ export function configFactory(
}),
],

snapshot: {
managedPaths: componentPathsRegExps,
},

watchOptions: {
poll: true,
},
Expand Down
13 changes: 12 additions & 1 deletion scopes/webpack/webpack/webpack.main.runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class WebpackMain {
context.id,
context.rootPath,
context.publicPath,
this.workspace.getComponentPathsRegExps(),
context.title
) as any;
const wdsPath = webpackDevServerModulePath || require.resolve('webpack-dev-server');
Expand Down Expand Up @@ -197,9 +198,19 @@ export class WebpackMain {
devServerID: string,
publicRoot: string,
publicPath: string,
componentPathsRegExps: RegExp[],
title?: string
) {
return devServerConfigFactory(devServerID, rootPath, entry, publicRoot, publicPath, this.pubsub, title);
return devServerConfigFactory(
devServerID,
rootPath,
entry,
publicRoot,
publicPath,
componentPathsRegExps,
this.pubsub,
title
);
}

static slots = [];
Expand Down
1 change: 1 addition & 0 deletions scopes/workspace/workspace/workspace.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ export default async function provideWorkspace(
componentIds.forEach((id) => {
workspace.clearComponentCache(id);
});
await workspace.setComponentPathsRegExps();
});

// add sub-commands "set" and "unset" to envs command.
Expand Down
36 changes: 36 additions & 0 deletions scopes/workspace/workspace/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { PubsubMain } from '@teambit/pubsub';
import { IssuesList } from '@teambit/component-issues';
import type { AspectLoaderMain, AspectDefinition } from '@teambit/aspect-loader';
import DependencyGraph from '@teambit/legacy/dist/scope/graph/scope-graph';
import { generateNodeModulesPattern, PatternTarget } from '@teambit/dependencies.modules.packages-excluder';
import {
AspectEntry,
ComponentMain,
Expand Down Expand Up @@ -151,6 +152,11 @@ export class Workspace implements ComponentFactory {
private componentLoadedSelfAsAspects: InMemoryCache<boolean>; // cache loaded components
private aspectsMerger: AspectsMerger;
private componentDefaultScopeFromComponentDirAndNameWithoutConfigFileMemoized;
/**
* Components paths are calculated from the component package names of the workspace
* They are used in webpack configuration to only track changes from these paths inside `node_modules`
*/
private componentPathsRegExps: RegExp[] = [];
localAspects: string[] = [];
constructor(
/**
Expand Down Expand Up @@ -235,6 +241,22 @@ export class Workspace implements ComponentFactory {
}
);
this.aspectsMerger = new AspectsMerger(this, this.harmony);

this.registerOnComponentAdd(async () => {
await this.setComponentPathsRegExps();
return {
results: this.componentPathsRegExps,
toString: () => this.componentPathsRegExps.join(),
};
});

this.registerOnComponentRemove(async () => {
await this.setComponentPathsRegExps();
return {
results: this.componentPathsRegExps,
toString: () => this.componentPathsRegExps.join(),
};
});
}

private validateConfig() {
Expand Down Expand Up @@ -1785,6 +1807,20 @@ the following envs are used in this workspace: ${availableEnvs.join(', ')}`);
await this.bitMap.write();
return { updated, alreadyUpToDate };
}

getComponentPathsRegExps() {
return this.componentPathsRegExps;
}

async setComponentPathsRegExps() {
const workspaceComponents = await this.list();
const workspacePackageNames = workspaceComponents.map((c) => this.componentPackageName(c));
const pathsExcluding = generateNodeModulesPattern({
packages: workspacePackageNames,
format: PatternTarget.WEBPACK,
});
this.componentPathsRegExps = [...pathsExcluding.map((stringPattern) => new RegExp(stringPattern))];
}
}

/**
Expand Down