Skip to content

Commit

Permalink
fix: externalize node_modules
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS committed Dec 11, 2024
1 parent ef12696 commit 05db4ed
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 13 deletions.
9 changes: 0 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"prettier": "prettier '**/*.{md,yaml,yml,json}'",
"typecheck": "tsc --noEmit",
"test": "jest",
"watch": "tsc -p tsconfig.production.json --watch",
"build": "npm run build:clean && npm run build:compile",
"build:compile": "tsc -p tsconfig.production.json",
"build:clean": "rimraf dist",
Expand Down Expand Up @@ -129,7 +130,6 @@
"webpack-bundle-analyzer": "^4.10.2",
"webpack-dev-server": "^5.1.0",
"webpack-manifest-plugin": "^5.0.0",
"webpack-node-externals": "^3.0.0",
"worker-loader": "^3.0.8",
"yargs": "^17.7.2"
},
Expand Down
6 changes: 3 additions & 3 deletions src/common/webpack/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import MomentTimezoneDataPlugin from 'moment-timezone-data-webpack-plugin';
import StatoscopeWebpackPlugin from '@statoscope/webpack-plugin';
import CircularDependencyPlugin from 'circular-dependency-plugin';
import type {sentryWebpackPlugin} from '@sentry/webpack-plugin';
import nodeExternals from 'webpack-node-externals';

import type TerserWebpackPlugin from 'terser-webpack-plugin';
import type * as Lightningcss from 'lightningcss';
Expand All @@ -30,6 +29,7 @@ import {resolveTsConfigPathsToAlias} from './utils';
import {S3UploadPlugin} from '../s3-upload';
import {logConfig} from '../logger/log-config';
import {resolveTypescript} from '../typescript/utils';
import {nodeExternals} from './node-externals';

const imagesSizeLimit = 2048;
const fontSizeLimit = 8192;
Expand Down Expand Up @@ -75,8 +75,8 @@ export async function webpackConfigFactory(
config.ssr?.noExternal === true
? undefined
: nodeExternals({
allowlist: config.ssr?.noExternal,
importType: config.ssr?.moduleType === 'esm' ? 'module' : 'commonjs',
noExternal: config.ssr?.noExternal,
module: config.ssr?.moduleType === 'esm',
});
}

Expand Down
108 changes: 108 additions & 0 deletions src/common/webpack/node-externals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import type * as webpack from 'webpack';
import paths from '../paths';

type Pattern = RegExp | ((v: string) => boolean) | string;

export interface NodeExternalsOptions {
noExternal?: Pattern | Pattern[];
module?: boolean;
}

const webpackInternal = /^webpack\/container\/reference\//;

export function nodeExternals({noExternal = [], module}: NodeExternalsOptions) {
const noExternals = Array<Pattern>().concat(webpackInternal).concat(noExternal);

const nodeModules = readPackagesNames(paths.appNodeModules);

return async (data: webpack.ExternalItemFunctionData) => {
const {request} = data;
if (!request) {
return undefined;
}

const moduleName = getModuleName(request);
if (
!request ||
!containsPattern(nodeModules, moduleName) ||
containsPattern(noExternals, request)
) {
return undefined;
}

if (!module) {
return `commonjs ${data.request}`;
}

if (
data.dependencyType === 'commonjs' ||
// lodash/something without extension can't be imported so always require it
(moduleName === 'lodash' && request.match(/^lodash\/[\w_]+($|\/[\w_]+$)/))
) {
return `node-commonjs ${data.request}`;
}

return `module-import ${data.request}`;
};
}

function readPackagesNames(dirName: string) {
if (!fs.existsSync(dirName)) {
return [];
}

try {
return fs
.readdirSync(dirName)
.map((module) => {
if (
module.startsWith('.') ||
!fs.statSync(path.join(dirName, module)).isDirectory()
) {
return undefined;
}
if (module.startsWith('@')) {
try {
return fs.readdirSync(path.join(dirName, module)).map(function (scopedMod) {
return module + '/' + scopedMod;
});
} catch (e) {
return [module];
}
}
return module;
})
.flat()
.filter((v) => v !== undefined);
} catch (e) {
return [];
}
}

function containsPattern(patterns: Pattern[], value: string) {
return patterns.some((pattern) => {
if (pattern instanceof RegExp) {
return pattern.test(value);
} else if (typeof pattern === 'function') {
return pattern(value);
} else {
return pattern === value;
}
});
}

function getModuleName(request: string) {
const req = request;
const delimiter = '/';

// check if scoped module
if (req.startsWith('@')) {
const parts = req.split(delimiter, 2);
if (parts.length === 2) {
return parts.join(delimiter);
}
}
return req.split(delimiter, 1)[0] || '';
}

0 comments on commit 05db4ed

Please sign in to comment.