Fix detection of child directories

Using `string.startsWith` is insufficient when two different directories
share a prefix, e.g. `./packageA` and `./packageAA`.
This commit is contained in:
Joel Low
2021-01-07 17:00:41 +08:00
parent 3a6f0539d3
commit 818d45e942
5 changed files with 48 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Fix detection of external package child directories
@@ -84,6 +84,23 @@ describe('LinkedPackageResolvePlugin', () => {
expect(callbackFalse).toHaveBeenCalledWith();
expect(doResolve).toHaveBeenCalledTimes(0);
// Internal modules with a path prefix of an external module
const callbackY = jest.fn();
tap(
{
request: path.resolve(root, 'external-aa/src/module.ts'),
path: path.resolve(root, 'external-aa/src'),
context: {
issuer: path.resolve(root, 'external-aa/src/index.ts'),
},
},
'some-context',
callbackY,
);
expect(callbackY).toHaveBeenCalledTimes(1);
expect(callbackY).toHaveBeenCalledWith();
expect(doResolve).toHaveBeenCalledTimes(0);
// External modules have their path and issuer context rewritten, but not the request
const callbackA = jest.fn();
tap(
@@ -16,6 +16,7 @@
import { resolve as resolvePath } from 'path';
import { ResolvePlugin } from 'webpack';
import { isChildPath } from './paths';
import { LernaPackage } from './types';
// Enables proper resolution of packages when linking in external packages.
@@ -40,7 +41,7 @@ export class LinkedPackageResolvePlugin implements ResolvePlugin {
callback: () => void,
) => {
const pkg = this.packages.find(
pkg => data.path && data.path.startsWith(pkg.location),
pkg => data.path && isChildPath(pkg.location, data.path),
);
if (!pkg) {
callback();
+7 -3
View File
@@ -24,7 +24,7 @@ import webpack from 'webpack';
import nodeExternals from 'webpack-node-externals';
import { optimization } from './optimization';
import { Config } from '@backstage/config';
import { BundlingPaths } from './paths';
import { BundlingPaths, isChildPath } from './paths';
import { transforms } from './transforms';
import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin';
import { BundlingOptions, BackendBundlingOptions, LernaPackage } from './types';
@@ -87,7 +87,9 @@ export async function createConfig(
const { plugins, loaders } = transforms(options);
// Any package that is part of the monorepo but outside the monorepo root dir need
// separate resolution logic.
const externalPkgs = packages.filter(p => !p.location.startsWith(paths.root));
const externalPkgs = packages.filter(
p => !isChildPath(paths.root, p.location),
);
const baseUrl = frontendConfig.getString('app.baseUrl');
const validBaseUrl = new URL(baseUrl);
@@ -199,7 +201,9 @@ export async function createBackendConfig(
const moduleDirs = packages.map((p: any) =>
resolvePath(p.location, 'node_modules'),
);
const externalPkgs = packages.filter(p => !p.location.startsWith(paths.root)); // See frontend config
const externalPkgs = packages.filter(
p => !isChildPath(paths.root, p.location),
); // See frontend config
const { loaders } = transforms(options);
+17
View File
@@ -15,8 +15,25 @@
*/
import fs from 'fs-extra';
import path from 'path';
import { paths } from '../paths';
/**
* Checks if dir is the same as or a child of base.
*/
export function isChildPath(base: string, dir: string): boolean {
const relativePath = path.relative(base, dir);
if (relativePath === '') {
// The same directory
return true;
}
const outsideBase = relativePath.startsWith('..'); // not outside base
const differentDrive = path.isAbsolute(relativePath); // on Windows, this means dir is on a different drive from base.
return !outsideBase && !differentDrive;
}
export type BundlingPathsOptions = {
// bundle entrypoint, e.g. 'src/index'
entry: string;