mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Make webpack respect dependencies vs peerDependencies when deciding dependency is external (#7545)
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
1 parent
adf67fb6a7
commit
7dc0ce7192
19 files changed
+231
-44
No files matched your search
@@ -33,7 +33,6 @@
|
||||
"tailwindcss": "^3.3.1",
|
||||
"ts-loader": "^9.4.1",
|
||||
"webpack": "^5.77.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
"webpack-cli": "^4.10.0"
|
||||
}
|
||||
}
|
||||
+9
-12
@@ -6,10 +6,6 @@ Array [
|
||||
"entry": Object {
|
||||
"index": "./index.ts",
|
||||
},
|
||||
"externals": Array [
|
||||
[Function],
|
||||
[Function],
|
||||
],
|
||||
"externalsPresets": Object {
|
||||
"node": true,
|
||||
},
|
||||
@@ -37,6 +33,8 @@ Array [
|
||||
"maxEntrypointSize": 100000,
|
||||
},
|
||||
"plugins": Array [
|
||||
MakePeerDependenciesExternalPlugin {},
|
||||
ProtectFromImportingNonDependencies {},
|
||||
ForkTsCheckerWebpackPlugin {
|
||||
"options": Object {
|
||||
"typescript": Object {
|
||||
@@ -58,6 +56,7 @@ Array [
|
||||
"extensions": Array [
|
||||
".ts",
|
||||
".tsx",
|
||||
".js",
|
||||
],
|
||||
},
|
||||
"target": "node",
|
||||
@@ -66,10 +65,6 @@ Array [
|
||||
"entry": Object {
|
||||
"index": "./some-entrypoint/index.ts",
|
||||
},
|
||||
"externals": Array [
|
||||
[Function],
|
||||
[Function],
|
||||
],
|
||||
"externalsPresets": Object {
|
||||
"node": true,
|
||||
},
|
||||
@@ -97,6 +92,8 @@ Array [
|
||||
"maxEntrypointSize": 100000,
|
||||
},
|
||||
"plugins": Array [
|
||||
MakePeerDependenciesExternalPlugin {},
|
||||
ProtectFromImportingNonDependencies {},
|
||||
ForkTsCheckerWebpackPlugin {
|
||||
"options": Object {
|
||||
"typescript": Object {
|
||||
@@ -118,6 +115,7 @@ Array [
|
||||
"extensions": Array [
|
||||
".ts",
|
||||
".tsx",
|
||||
".js",
|
||||
],
|
||||
},
|
||||
"target": "node",
|
||||
@@ -126,10 +124,6 @@ Array [
|
||||
"entry": Object {
|
||||
"index": "./some-other-entrypoint/index.ts",
|
||||
},
|
||||
"externals": Array [
|
||||
[Function],
|
||||
[Function],
|
||||
],
|
||||
"externalsPresets": Object {
|
||||
"node": true,
|
||||
},
|
||||
@@ -205,6 +199,8 @@ Array [
|
||||
"maxEntrypointSize": 100000,
|
||||
},
|
||||
"plugins": Array [
|
||||
MakePeerDependenciesExternalPlugin {},
|
||||
ProtectFromImportingNonDependencies {},
|
||||
ForkTsCheckerWebpackPlugin {
|
||||
"options": Object {
|
||||
"typescript": Object {
|
||||
@@ -241,6 +237,7 @@ Array [
|
||||
"extensions": Array [
|
||||
".ts",
|
||||
".tsx",
|
||||
".js",
|
||||
],
|
||||
},
|
||||
"target": "node",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const ForkTsCheckerPlugin = require("fork-ts-checker-webpack-plugin");
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
const path = require("path");
|
||||
const { MakePeerDependenciesExternalPlugin } = require("./plugins/make-peer-dependencies-external");
|
||||
const { ProtectFromImportingNonDependencies } = require("./plugins/protect-from-importing-non-dependencies");
|
||||
|
||||
module.exports = ({ entrypointFilePath, outputDirectory }) => ({
|
||||
name: entrypointFilePath,
|
||||
@@ -14,10 +14,13 @@ module.exports = ({ entrypointFilePath, outputDirectory }) => ({
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [".ts", ".tsx"],
|
||||
extensions: [".ts", ".tsx", ".js"],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new MakePeerDependenciesExternalPlugin(),
|
||||
new ProtectFromImportingNonDependencies(),
|
||||
|
||||
new ForkTsCheckerPlugin({
|
||||
typescript: {
|
||||
mode: "write-dts",
|
||||
@@ -45,21 +48,6 @@ module.exports = ({ entrypointFilePath, outputDirectory }) => ({
|
||||
libraryTarget: "commonjs2",
|
||||
},
|
||||
|
||||
externals: [
|
||||
nodeExternals({ modulesFromFile: true }),
|
||||
|
||||
nodeExternals({
|
||||
modulesDir: path.resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"node_modules"
|
||||
),
|
||||
}),
|
||||
],
|
||||
|
||||
externalsPresets: { node: true },
|
||||
|
||||
node: {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const getDependencyName = (requireString) => {
|
||||
const [a, b] = requireString.split("/");
|
||||
|
||||
const scoped = a.startsWith("@");
|
||||
|
||||
return scoped ? `${a}/${b}` : a;
|
||||
};
|
||||
|
||||
module.exports = { getDependencyName };
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { getDependencyName } from "./get-dependency-name";
|
||||
|
||||
describe("get-dependency-name", () => {
|
||||
it("given scoped dependency with entrypoint, returns dependency name", () => {
|
||||
const actual = getDependencyName("@some-scope/some-package/entrypoint");
|
||||
|
||||
expect(actual).toBe("@some-scope/some-package");
|
||||
});
|
||||
|
||||
it("given scoped dependency but no entrypoint, returns dependency name", () => {
|
||||
const actual = getDependencyName("@some-scope/some-package");
|
||||
|
||||
expect(actual).toBe("@some-scope/some-package");
|
||||
});
|
||||
|
||||
it("given non scoped dependency with entrypoint, returns dependency name", () => {
|
||||
const actual = getDependencyName("some-package/some-entrypoint");
|
||||
|
||||
expect(actual).toBe("some-package");
|
||||
});
|
||||
|
||||
it("given non scoped dependency but no entrypoint, returns dependency name", () => {
|
||||
const actual = getDependencyName("some-package");
|
||||
|
||||
expect(actual).toBe("some-package");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
const ExternalModuleFactoryPlugin = require("webpack/lib/ExternalModuleFactoryPlugin");
|
||||
const path = require("path");
|
||||
|
||||
const {
|
||||
toModuleMatcherRegExp,
|
||||
} = require("./to-module-matcher-reg-exp/to-module-matcher-reg-exp");
|
||||
|
||||
class MakePeerDependenciesExternalPlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.compile.tap("compile", (params) => {
|
||||
const peerDependencies = getPeerDependencies();
|
||||
|
||||
new ExternalModuleFactoryPlugin(
|
||||
compiler.options.output.library.type,
|
||||
peerDependencies.map(toModuleMatcherRegExp)
|
||||
).apply(params.normalModuleFactory);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const getPeerDependencies = () => {
|
||||
const pathToPackageJson = path.resolve(process.cwd(), "package.json");
|
||||
|
||||
const packageJson = require(pathToPackageJson);
|
||||
|
||||
return Object.keys(packageJson.peerDependencies || {});
|
||||
};
|
||||
|
||||
module.exports = { MakePeerDependenciesExternalPlugin };
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
const path = require("path");
|
||||
const { getDependencyName } = require("./get-dependency-name/get-dependency-name");
|
||||
|
||||
const pathToPackageJson = path.resolve(process.cwd(), "package.json");
|
||||
|
||||
class ProtectFromImportingNonDependencies {
|
||||
apply(compiler) {
|
||||
const dependencies = getDependenciesAndPeerDependencies();
|
||||
|
||||
const nodeModulesToBeResolved = new Set();
|
||||
|
||||
compiler.hooks.normalModuleFactory.tap("irrelevant", (normalModuleFactory) => {
|
||||
normalModuleFactory.hooks.resolve.tap("irrelevant", (toBeResolved) => {
|
||||
|
||||
const isLocalDependency = toBeResolved.request.startsWith(".");
|
||||
const isDependencyOfDependency =
|
||||
toBeResolved.context.includes("node_modules");
|
||||
|
||||
if (!isLocalDependency && !isDependencyOfDependency) {
|
||||
|
||||
const dependencyName = getDependencyName(toBeResolved.request);
|
||||
|
||||
nodeModulesToBeResolved.add(dependencyName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
compiler.hooks.afterCompile.tap("compile", () => {
|
||||
const notSpecifiedDependencies = [...nodeModulesToBeResolved].filter(
|
||||
(x) => !dependencies.includes(x)
|
||||
);
|
||||
|
||||
if (notSpecifiedDependencies.length) {
|
||||
throw new Error(
|
||||
`Tried to import dependencies that are not specified in the package.json "${pathToPackageJson}". Add "${notSpecifiedDependencies.join(
|
||||
'", "'
|
||||
)}" to dependencies or peerDependencies.`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
const getDependenciesAndPeerDependencies = () => {
|
||||
const packageJson = require(pathToPackageJson);
|
||||
|
||||
const dependencies = Object.keys(packageJson.dependencies || {});
|
||||
const peerDependencies = Object.keys(packageJson.peerDependencies || {});
|
||||
|
||||
return [...dependencies, ...peerDependencies];
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
ProtectFromImportingNonDependencies,
|
||||
};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const toModuleMatcherRegExp = x => new RegExp(`^${x}(/.*)*$`);
|
||||
|
||||
module.exports = { toModuleMatcherRegExp };
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { toModuleMatcherRegExp } from "./to-module-matcher-reg-exp";
|
||||
|
||||
describe('to-module-matcher-reg-exp', () => {
|
||||
let regExp;
|
||||
|
||||
beforeEach(() => {
|
||||
regExp = toModuleMatcherRegExp("some-package");
|
||||
});
|
||||
|
||||
it('given exactly matching package, matches', () => {
|
||||
const targetString = 'some-package';
|
||||
|
||||
const [match] = targetString.match(regExp);
|
||||
|
||||
expect(match).toBeTruthy()
|
||||
});
|
||||
|
||||
it('given matching package with entrypoint, matches', () => {
|
||||
const targetString = 'some-package/some-entrypoint';
|
||||
|
||||
const [match] = targetString.match(regExp);
|
||||
|
||||
expect(match).toBeTruthy()
|
||||
});
|
||||
|
||||
it('given matching package with directory, matches', () => {
|
||||
const targetString = 'some-package/some-directory/some-other-directory';
|
||||
|
||||
const [match] = targetString.match(regExp);
|
||||
|
||||
expect(match).toBeTruthy()
|
||||
});
|
||||
|
||||
it('given package that starts with same name but is still different, does not match', () => {
|
||||
const targetString = 'some-package-but-still-different';
|
||||
|
||||
const actual = targetString.match(regExp);
|
||||
|
||||
expect(actual).toBeNull()
|
||||
});
|
||||
|
||||
it('given package that starts with something else, does not match', () => {
|
||||
const targetString = 'different-some-package';
|
||||
|
||||
const actual = targetString.match(regExp);
|
||||
|
||||
expect(actual).toBeNull()
|
||||
});
|
||||
|
||||
it('given irrelevant package, does not match', () => {
|
||||
const targetString = 'some-other-package';
|
||||
|
||||
const actual = targetString.match(regExp);
|
||||
|
||||
expect(actual).toBeNull()
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user