Skip to content

Commit 5d8156e

Browse files
ci: checks for bundling (#632)
* ci: checks for bundling * ci: test bundle ability
1 parent d2d89ec commit 5d8156e

File tree

7 files changed

+323
-1
lines changed

7 files changed

+323
-1
lines changed

.github/workflows/test.yml

+13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ jobs:
1010
uses: ./.github/workflows/unitTestsLinux.yml
1111
windows-unit-tests:
1212
uses: ./.github/workflows/unitTestsWindows.yml
13+
test-bundle:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: lts/*
20+
cache: yarn
21+
- uses: salesforcecli/github-workflows/.github/actions/yarnInstallWithRetries@main
22+
- name: Build the project
23+
run: yarn build
24+
- name: check if bundling runs into failures
25+
run: node scripts/testEsbuild.js
1326
external-test:
1427
name: run tests in plugin-templates
1528
runs-on: 'ubuntu-latest'

.husky/pre-commit

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
. "$(dirname -- "$0")/_/husky.sh"
33

44
yarn lint && yarn pretty-quick --staged
5+
node ./scripts/scanTs.js

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"chai-as-promised": "^7.1.2",
3838
"commitizen": "^4.3.1",
3939
"cz-conventional-changelog": "^3.3.0",
40+
"esbuild": "^0.24.0",
4041
"eslint": "^7.27.0",
4142
"eslint-config-prettier": "^6.11.0",
4243
"eslint-config-salesforce": "^0.1.6",
@@ -54,6 +55,7 @@
5455
"shelljs": "^0.8.5",
5556
"shx": "^0.3.4",
5657
"sinon": "^18",
58+
"ts-morph": "^24.0.0",
5759
"ts-node": "^10.9.2",
5860
"typescript": "^5.4.5"
5961
},
@@ -79,4 +81,4 @@
7981
"publishConfig": {
8082
"access": "public"
8183
}
82-
}
84+
}

scripts/esbuild.config.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* NOTE: This file does NOT really generate a bundle version of templates
3+
* templates is bundled directly in salesforcedx-vscode
4+
* The file is only used to detect any potential risks to esbuild.
5+
**/
6+
const { build } = require('esbuild');
7+
8+
const sharedConfig = {
9+
bundle: true,
10+
format: 'cjs',
11+
platform: 'node',
12+
external: [], // The allowlist of dependencies that are not bundle-able
13+
keepNames: true,
14+
plugins: [],
15+
supported: {
16+
'dynamic-import': false,
17+
},
18+
logOverride: {
19+
'unsupported-dynamic-import': 'error',
20+
},
21+
};
22+
23+
(async () => {
24+
await build({
25+
...sharedConfig,
26+
entryPoints: ['./lib/index.js'],
27+
outdir: 'dist',
28+
});
29+
})();

scripts/scanTs.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const { Project, CallExpression } = require('ts-morph');
4+
5+
const SRC_DIR = path.join(__dirname, '..', 'src');
6+
const project = new Project({
7+
tsConfigFilePath: path.join(__dirname, '..', 'tsconfig.json'),
8+
});
9+
10+
let detected = false;
11+
12+
const scanDirectory = (dir) => {
13+
const files = fs.readdirSync(dir);
14+
files.forEach((file) => {
15+
const fullPath = path.join(dir, file);
16+
const stat = fs.statSync(fullPath);
17+
if (stat.isDirectory()) {
18+
scanDirectory(fullPath);
19+
} else if (fullPath.endsWith('.ts')) {
20+
analyzeFile(fullPath);
21+
}
22+
});
23+
};
24+
25+
// This function will detect all the usages of fs.read* and send warnings with the location of the usage
26+
const analyzeFile = (filePath) => {
27+
const srcFile = project.addSourceFileAtPath(filePath);
28+
const funcCalls = srcFile.getDescendantsOfKind(CallExpression);
29+
30+
funcCalls.forEach((callExpression) => {
31+
const exp = callExpression.getExpression();
32+
if (exp.getText().startsWith('fs.read')) {
33+
detected = true;
34+
console.warn(
35+
`Warning: Usage of "${exp.getText()}" in file "${filePath}" at line ${callExpression.getStartLineNumber()}.\n`
36+
);
37+
}
38+
});
39+
};
40+
41+
scanDirectory(SRC_DIR);
42+
43+
if (detected) {
44+
console.log('The warnings above do not mean the usages are wrong.');
45+
console.log(
46+
`Avoid reading local artifacts with "fs.read*" since esbuild cannot bundle the artifacts together.`
47+
);
48+
console.log(
49+
'Consider using import instead or reach out to IDEx Foundations team'
50+
);
51+
} else {
52+
console.log('No fs.read* usages detected.');
53+
}
54+
55+
console.log('Scan complete');

scripts/testEsbuild.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const { exec } = require('child_process');
2+
3+
// Run the command
4+
exec('node ./scripts/esbuild.config.js', (error, stdout, stderr) => {
5+
// Combine stdout and stderr to check the entire output
6+
const output = `${stdout}\n${stderr}`;
7+
if (error) {
8+
console.error(stderr);
9+
process.exit(1); // Exit with an error code
10+
}
11+
// Check if the output contains the error string
12+
if (output.includes('[require-resolve-not-external]')) {
13+
console.error(
14+
'Error: A dependency that has to be externalized in esbuild process is found. Please resolve it!'
15+
);
16+
process.exit(1); // Exit with an error code
17+
} else {
18+
process.exit(0); // Exit with success code
19+
}
20+
});

0 commit comments

Comments
 (0)