Skip to content

Commit ec1af5a

Browse files
authored
chore(devextreme): migrate build:vectormap target to nx executors (#33368)
1 parent a32e237 commit ec1af5a

15 files changed

Lines changed: 2231 additions & 521 deletions

File tree

.github/copilot-instructions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ pnpm exec nx build:localization devextreme # Generate localization files
166166
pnpm exec nx build:transpile devextreme # Transpile source code
167167
pnpm exec nx bundle:debug devextreme # Create debug bundle
168168
pnpm exec nx bundle:prod devextreme # Create production bundle
169+
pnpm exec nx build:vectormap devextreme # Build vectormap utils + region data
169170
pnpm exec nx build:npm devextreme # Prepare NPM packages
170171
```
171172

@@ -192,6 +193,7 @@ The `packages/nx-infra-plugin` provides custom Nx executors for build automation
192193
| `build-typescript` | Compiles TypeScript to CJS or ESM modules with configurable output format, tsconfig, and path alias resolution |
193194
| `bundle` | Bundles JavaScript files using webpack with debug or production mode, supporting multiple entry points and license validation |
194195
| `clean` | Removes directories and files with support for exclusion patterns |
196+
| `compress` | Minifies or beautifies JavaScript files, with optional debug block stripping |
195197
| `concatenate-files` | Concatenates files with optional content extraction via regex, header/footer, and find/replace transforms |
196198
| `copy-files` | Copies files and directories to specified destinations with glob pattern support |
197199
| `create-dual-mode-manifest` | Generates package.json files for dual-mode (ESM + CJS) support with main, module, typings, and sideEffects |
@@ -202,6 +204,7 @@ The `packages/nx-infra-plugin` provides custom Nx executors for build automation
202204
| `pack-npm` | Creates npm packages using `pnpm pack` for distribution |
203205
| `prepare-package-json` | Creates distribution-ready package.json with cleaned dependencies for npm publishing |
204206
| `prepare-submodules` | Creates package.json entry points for submodule exports |
207+
| `vectormap` | Builds vectormap utility UMD bundles (`dx.vectormaputils.*.js`) and geographic region data modules from shapefile sources and JST templates |
205208

206209
**Example executor usage in project.json:**
207210
```json

packages/devextreme/gulpfile.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const multiProcess = require('gulp-multi-process');
66
const env = require('./build/gulp/env-variables');
77
const cache = require('gulp-cache');
88
const shell = require('gulp-shell');
9-
const { REMOVE_NON_PRODUCTION_MODULE } = require('./build/gulp/context');
9+
const context = require('./build/gulp/context');
10+
const { REMOVE_NON_PRODUCTION_MODULE } = context;
1011

1112
gulp.task('clean', function(callback) {
1213
require('del').sync([
@@ -30,7 +31,6 @@ gulp.task('clean', function(callback) {
3031
require('./build/gulp/bundler-config');
3132
require('./build/gulp/transpile');
3233
require('./build/gulp/js-bundles');
33-
require('./build/gulp/vectormap');
3434
require('./build/gulp/npm');
3535
require('./build/gulp/aspnet');
3636
require('./build/gulp/vendor');
@@ -60,6 +60,12 @@ gulp.task('transpile', shell.task(
6060
: 'pnpm nx run devextreme:build:transpile'
6161
));
6262

63+
gulp.task('vectormap', shell.task(
64+
context.uglify
65+
? 'pnpm nx run devextreme:build:vectormap -c production'
66+
: 'pnpm nx run devextreme:build:vectormap'
67+
));
68+
6369
if(env.TEST_CI) {
6470
console.warn('Using test CI mode!');
6571
}

packages/devextreme/project.json

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -675,19 +675,107 @@
675675
"{projectRoot}/artifacts/js/dx.ai-integration.js"
676676
]
677677
},
678+
"build:vectormap:generate": {
679+
"executor": "devextreme-nx-infra-plugin:vectormap",
680+
"options": {
681+
"sourceDir": "./js/viz/vector_map.utils",
682+
"settingsFile": "./_settings.json",
683+
"sourcesDir": "./build/vectormap-sources",
684+
"sourcesSettingsFile": "./_settings.js",
685+
"utilsOutDir": "./artifacts/js/vectormap-utils",
686+
"dataOutDir": "./artifacts/js/vectormap-data",
687+
"utilsTemplatePath": "./build/gulp/vectormaputils-template.jst",
688+
"dataTemplatePath": "./build/gulp/vectormapdata-template.jst"
689+
},
690+
"inputs": [
691+
"{projectRoot}/js/viz/vector_map.utils/**/*",
692+
"{projectRoot}/build/vectormap-sources/**/*",
693+
"{projectRoot}/build/gulp/vectormaputils-template.jst",
694+
"{projectRoot}/build/gulp/vectormapdata-template.jst"
695+
],
696+
"outputs": [
697+
"{projectRoot}/artifacts/js/vectormap-utils",
698+
"{projectRoot}/artifacts/js/vectormap-data"
699+
]
700+
},
701+
"build:vectormap:headers": {
702+
"executor": "devextreme-nx-infra-plugin:add-license-headers",
703+
"options": {
704+
"targetDirectory": "./artifacts/js/vectormap-utils",
705+
"licenseTemplateFile": "./build/gulp/license-header.txt",
706+
"eulaUrl": "https://js.devexpress.com/Licensing/",
707+
"separatorBetweenBannerAndContent": "",
708+
"prependAfterLicense": "\"use strict\";\n\n"
709+
},
710+
"inputs": [
711+
"{projectRoot}/artifacts/js/vectormap-utils/**/*",
712+
"{projectRoot}/build/gulp/license-header.txt"
713+
],
714+
"outputs": [
715+
"{projectRoot}/artifacts/js/vectormap-utils"
716+
]
717+
},
718+
"compress:vectormap:strip-debug": {
719+
"executor": "devextreme-nx-infra-plugin:compress",
720+
"options": {
721+
"files": [
722+
"./artifacts/js/vectormap-utils/dx.vectormaputils.js"
723+
],
724+
"mode": "strip-only"
725+
}
726+
},
727+
"compress:vectormap:beautify": {
728+
"executor": "devextreme-nx-infra-plugin:compress",
729+
"options": {
730+
"files": [
731+
"./artifacts/js/vectormap-utils/dx.vectormaputils.debug.js"
732+
],
733+
"mode": "beautify",
734+
"eulaUrl": "https://js.devexpress.com/Licensing/"
735+
}
736+
},
737+
"compress:vectormap:minify": {
738+
"executor": "devextreme-nx-infra-plugin:compress",
739+
"options": {
740+
"files": [
741+
"./artifacts/js/vectormap-utils/dx.vectormaputils.js"
742+
],
743+
"mode": "minify",
744+
"removeDebug": true,
745+
"eulaUrl": "https://js.devexpress.com/Licensing/"
746+
}
747+
},
678748
"build:vectormap": {
679749
"executor": "nx:run-commands",
680750
"options": {
681-
"command": "gulp vectormap",
682-
"cwd": "{projectRoot}"
751+
"commands": [
752+
"pnpm nx build:vectormap:generate devextreme",
753+
"pnpm nx build:vectormap:headers devextreme",
754+
"pnpm nx compress:vectormap:strip-debug devextreme"
755+
],
756+
"parallel": false
683757
},
684758
"inputs": [
685-
"{projectRoot}/build/gulp/vectormap.js"
759+
"{projectRoot}/js/viz/vector_map.utils/**/*",
760+
"{projectRoot}/build/vectormap-sources/**/*",
761+
"{projectRoot}/build/gulp/vectormaputils-template.jst",
762+
"{projectRoot}/build/gulp/vectormapdata-template.jst",
763+
"{projectRoot}/build/gulp/license-header.txt"
686764
],
687765
"outputs": [
688766
"{projectRoot}/artifacts/js/vectormap-utils",
689767
"{projectRoot}/artifacts/js/vectormap-data"
690-
]
768+
],
769+
"configurations": {
770+
"production": {
771+
"commands": [
772+
"pnpm nx build:vectormap:generate devextreme",
773+
"pnpm nx build:vectormap:headers devextreme",
774+
"pnpm nx compress:vectormap:beautify devextreme",
775+
"pnpm nx compress:vectormap:minify devextreme"
776+
]
777+
}
778+
}
691779
},
692780
"build:aspnet": {
693781
"executor": "nx:run-commands",

packages/nx-infra-plugin/executors.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@
7979
"implementation": "./src/executors/bundle/executor",
8080
"schema": "./src/executors/bundle/schema.json",
8181
"description": "Bundle JavaScript files using webpack with debug or production mode"
82+
},
83+
"vectormap": {
84+
"implementation": "./src/executors/vectormap/executor",
85+
"schema": "./src/executors/vectormap/schema.json",
86+
"description": "Build vectormap utility bundles and geographic region data modules"
87+
},
88+
"compress": {
89+
"implementation": "./src/executors/compress/executor",
90+
"schema": "./src/executors/compress/schema.json",
91+
"description": "Compress JavaScript files"
8292
}
8393
}
8494
}

packages/nx-infra-plugin/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
"dependencies": {
1515
"fs-extra": "11.2.0",
1616
"glob": "11.1.0",
17+
"js-beautify": "1.15.4",
1718
"minimatch": "10.2.4",
1819
"lodash": "4.18.1",
1920
"normalize-path": "3.0.0",
2021
"rimraf": "3.0.2",
22+
"terser": "5.46.1",
2123
"tsc-alias": "1.8.16"
2224
},
2325
"peerDependencies": {
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
import executor from './executor';
4+
import { CompressExecutorSchema } from './schema';
5+
import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils';
6+
import { writeFileText, readFileText } from '../../utils';
7+
8+
const LICENSE_HEADER = `/*!
9+
* DevExtreme (test.js)
10+
* Version: 99.0.0
11+
*/
12+
`;
13+
14+
const SAMPLE_CODE = `${LICENSE_HEADER}"use strict";
15+
16+
function hello(name) {
17+
//#DEBUG
18+
console.log("debug only");
19+
//#ENDDEBUG
20+
var unused = 42;
21+
return "Hello, " + name;
22+
}
23+
24+
exports.hello = hello;
25+
`;
26+
27+
describe('CompressExecutor E2E', () => {
28+
let tempDir: string;
29+
let context = createMockContext();
30+
let projectDir: string;
31+
32+
beforeEach(async () => {
33+
tempDir = createTempDir('nx-compress-e2e-');
34+
context = createMockContext({ root: tempDir });
35+
projectDir = path.join(tempDir, 'packages', 'test-lib');
36+
fs.mkdirSync(projectDir, { recursive: true });
37+
});
38+
39+
afterEach(() => {
40+
cleanupTempDir(tempDir);
41+
});
42+
43+
it('should minify and strip debug blocks', async () => {
44+
const filePath = path.join(projectDir, 'test.js');
45+
await writeFileText(filePath, SAMPLE_CODE);
46+
47+
const options: CompressExecutorSchema = {
48+
files: ['./test.js'],
49+
mode: 'minify',
50+
removeDebug: true,
51+
};
52+
53+
const result = await executor(options, context);
54+
expect(result.success).toBe(true);
55+
56+
const output = await readFileText(filePath);
57+
58+
expect(output).toContain('/*!');
59+
expect(output).toContain('DevExtreme');
60+
61+
expect(output).not.toContain('debug only');
62+
expect(output).not.toContain('#DEBUG');
63+
64+
expect(output.length).toBeLessThan(SAMPLE_CODE.length);
65+
});
66+
67+
it('should minify but keep debug blocks', async () => {
68+
const filePath = path.join(projectDir, 'test.js');
69+
await writeFileText(filePath, SAMPLE_CODE);
70+
71+
const options: CompressExecutorSchema = {
72+
files: ['./test.js'],
73+
mode: 'minify',
74+
};
75+
76+
const result = await executor(options, context);
77+
expect(result.success).toBe(true);
78+
79+
const output = await readFileText(filePath);
80+
81+
expect(output).toContain('debug only');
82+
});
83+
84+
it('should beautify with selective compression and preserve license comments', async () => {
85+
const filePath = path.join(projectDir, 'test.js');
86+
await writeFileText(filePath, SAMPLE_CODE);
87+
88+
const options: CompressExecutorSchema = {
89+
files: ['./test.js'],
90+
mode: 'beautify',
91+
};
92+
93+
const result = await executor(options, context);
94+
expect(result.success).toBe(true);
95+
96+
const output = await readFileText(filePath);
97+
98+
expect(output).toContain('/*!');
99+
100+
expect(output.split('\n').length).toBeGreaterThan(5);
101+
102+
expect(output).not.toContain('unused');
103+
});
104+
});

0 commit comments

Comments
 (0)