Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ pnpm exec nx build:localization devextreme # Generate localization files
pnpm exec nx build:transpile devextreme # Transpile source code
pnpm exec nx bundle:debug devextreme # Create debug bundle
pnpm exec nx bundle:prod devextreme # Create production bundle
pnpm exec nx build:vectormap devextreme # Build vectormap utils + region data
pnpm exec nx build:npm devextreme # Prepare NPM packages
```

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

**Example executor usage in project.json:**
```json
Expand Down
10 changes: 8 additions & 2 deletions packages/devextreme/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const multiProcess = require('gulp-multi-process');
const env = require('./build/gulp/env-variables');
const cache = require('gulp-cache');
const shell = require('gulp-shell');
const { REMOVE_NON_PRODUCTION_MODULE } = require('./build/gulp/context');
const context = require('./build/gulp/context');
const { REMOVE_NON_PRODUCTION_MODULE } = context;

gulp.task('clean', function(callback) {
require('del').sync([
Expand All @@ -30,7 +31,6 @@ gulp.task('clean', function(callback) {
require('./build/gulp/bundler-config');
require('./build/gulp/transpile');
require('./build/gulp/js-bundles');
require('./build/gulp/vectormap');
require('./build/gulp/npm');
require('./build/gulp/aspnet');
require('./build/gulp/vendor');
Expand Down Expand Up @@ -60,6 +60,12 @@ gulp.task('transpile', shell.task(
: 'pnpm nx run devextreme:build:transpile'
));

gulp.task('vectormap', shell.task(
context.uglify
? 'pnpm nx run devextreme:build:vectormap -c production'
: 'pnpm nx run devextreme:build:vectormap'
));

if(env.TEST_CI) {
console.warn('Using test CI mode!');
}
Expand Down
96 changes: 92 additions & 4 deletions packages/devextreme/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -675,19 +675,107 @@
"{projectRoot}/artifacts/js/dx.ai-integration.js"
]
},
"build:vectormap:generate": {
"executor": "devextreme-nx-infra-plugin:vectormap",
"options": {
"sourceDir": "./js/viz/vector_map.utils",
"settingsFile": "./_settings.json",
"sourcesDir": "./build/vectormap-sources",
"sourcesSettingsFile": "./_settings.js",
"utilsOutDir": "./artifacts/js/vectormap-utils",
"dataOutDir": "./artifacts/js/vectormap-data",
"utilsTemplatePath": "./build/gulp/vectormaputils-template.jst",
"dataTemplatePath": "./build/gulp/vectormapdata-template.jst"
},
"inputs": [
"{projectRoot}/js/viz/vector_map.utils/**/*",
"{projectRoot}/build/vectormap-sources/**/*",
"{projectRoot}/build/gulp/vectormaputils-template.jst",
"{projectRoot}/build/gulp/vectormapdata-template.jst"
],
"outputs": [
"{projectRoot}/artifacts/js/vectormap-utils",
"{projectRoot}/artifacts/js/vectormap-data"
]
},
"build:vectormap:headers": {
"executor": "devextreme-nx-infra-plugin:add-license-headers",
"options": {
"targetDirectory": "./artifacts/js/vectormap-utils",
"licenseTemplateFile": "./build/gulp/license-header.txt",
"eulaUrl": "https://js.devexpress.com/Licensing/",
"separatorBetweenBannerAndContent": "",
"prependAfterLicense": "\"use strict\";\n\n"
},
"inputs": [
"{projectRoot}/artifacts/js/vectormap-utils/**/*",
"{projectRoot}/build/gulp/license-header.txt"
],
"outputs": [
"{projectRoot}/artifacts/js/vectormap-utils"
]
},
"compress:vectormap:strip-debug": {
"executor": "devextreme-nx-infra-plugin:compress",
"options": {
"files": [
"./artifacts/js/vectormap-utils/dx.vectormaputils.js"
],
"mode": "strip-only"
}
},
"compress:vectormap:beautify": {
"executor": "devextreme-nx-infra-plugin:compress",
"options": {
"files": [
"./artifacts/js/vectormap-utils/dx.vectormaputils.debug.js"
],
"mode": "beautify",
"eulaUrl": "https://js.devexpress.com/Licensing/"
}
},
"compress:vectormap:minify": {
"executor": "devextreme-nx-infra-plugin:compress",
"options": {
"files": [
"./artifacts/js/vectormap-utils/dx.vectormaputils.js"
],
"mode": "minify",
"removeDebug": true,
"eulaUrl": "https://js.devexpress.com/Licensing/"
}
},
"build:vectormap": {
"executor": "nx:run-commands",
"options": {
"command": "gulp vectormap",
"cwd": "{projectRoot}"
"commands": [
"pnpm nx build:vectormap:generate devextreme",
"pnpm nx build:vectormap:headers devextreme",
"pnpm nx compress:vectormap:strip-debug devextreme"
],
"parallel": false
},
"inputs": [
"{projectRoot}/build/gulp/vectormap.js"
"{projectRoot}/js/viz/vector_map.utils/**/*",
"{projectRoot}/build/vectormap-sources/**/*",
"{projectRoot}/build/gulp/vectormaputils-template.jst",
"{projectRoot}/build/gulp/vectormapdata-template.jst",
"{projectRoot}/build/gulp/license-header.txt"
],
"outputs": [
"{projectRoot}/artifacts/js/vectormap-utils",
"{projectRoot}/artifacts/js/vectormap-data"
]
],
"configurations": {
"production": {
"commands": [
"pnpm nx build:vectormap:generate devextreme",
"pnpm nx build:vectormap:headers devextreme",
"pnpm nx compress:vectormap:beautify devextreme",
"pnpm nx compress:vectormap:minify devextreme"
]
Comment thread
chaosmirage marked this conversation as resolved.
}
}
},
Comment thread
chaosmirage marked this conversation as resolved.
"build:aspnet": {
"executor": "nx:run-commands",
Expand Down
10 changes: 10 additions & 0 deletions packages/nx-infra-plugin/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@
"implementation": "./src/executors/bundle/executor",
"schema": "./src/executors/bundle/schema.json",
"description": "Bundle JavaScript files using webpack with debug or production mode"
},
"vectormap": {
"implementation": "./src/executors/vectormap/executor",
"schema": "./src/executors/vectormap/schema.json",
"description": "Build vectormap utility bundles and geographic region data modules"
},
"compress": {
"implementation": "./src/executors/compress/executor",
"schema": "./src/executors/compress/schema.json",
"description": "Compress JavaScript files"
}
}
}
2 changes: 2 additions & 0 deletions packages/nx-infra-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
"dependencies": {
"fs-extra": "11.2.0",
"glob": "11.1.0",
"js-beautify": "1.15.4",
"minimatch": "10.2.4",
"lodash": "4.18.1",
"normalize-path": "3.0.0",
"rimraf": "3.0.2",
"terser": "5.46.1",
"tsc-alias": "1.8.16"
},
"peerDependencies": {
Expand Down
104 changes: 104 additions & 0 deletions packages/nx-infra-plugin/src/executors/compress/executor.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as fs from 'fs';
import * as path from 'path';
import executor from './executor';
import { CompressExecutorSchema } from './schema';
import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils';
import { writeFileText, readFileText } from '../../utils';

const LICENSE_HEADER = `/*!
* DevExtreme (test.js)
* Version: 99.0.0
*/
`;

const SAMPLE_CODE = `${LICENSE_HEADER}"use strict";

function hello(name) {
//#DEBUG
console.log("debug only");
//#ENDDEBUG
var unused = 42;
return "Hello, " + name;
}

exports.hello = hello;
`;

describe('CompressExecutor E2E', () => {
let tempDir: string;
let context = createMockContext();
let projectDir: string;

beforeEach(async () => {
tempDir = createTempDir('nx-compress-e2e-');
context = createMockContext({ root: tempDir });
projectDir = path.join(tempDir, 'packages', 'test-lib');
fs.mkdirSync(projectDir, { recursive: true });
});

afterEach(() => {
cleanupTempDir(tempDir);
});

it('should minify and strip debug blocks', async () => {
const filePath = path.join(projectDir, 'test.js');
await writeFileText(filePath, SAMPLE_CODE);

const options: CompressExecutorSchema = {
files: ['./test.js'],
mode: 'minify',
removeDebug: true,
};

const result = await executor(options, context);
expect(result.success).toBe(true);

const output = await readFileText(filePath);

expect(output).toContain('/*!');
expect(output).toContain('DevExtreme');

expect(output).not.toContain('debug only');
expect(output).not.toContain('#DEBUG');

expect(output.length).toBeLessThan(SAMPLE_CODE.length);
});

it('should minify but keep debug blocks', async () => {
const filePath = path.join(projectDir, 'test.js');
await writeFileText(filePath, SAMPLE_CODE);

const options: CompressExecutorSchema = {
files: ['./test.js'],
mode: 'minify',
};

const result = await executor(options, context);
expect(result.success).toBe(true);

const output = await readFileText(filePath);

expect(output).toContain('debug only');
});

it('should beautify with selective compression and preserve license comments', async () => {
const filePath = path.join(projectDir, 'test.js');
await writeFileText(filePath, SAMPLE_CODE);

const options: CompressExecutorSchema = {
files: ['./test.js'],
mode: 'beautify',
};

const result = await executor(options, context);
expect(result.success).toBe(true);

const output = await readFileText(filePath);

expect(output).toContain('/*!');

expect(output.split('\n').length).toBeGreaterThan(5);

expect(output).not.toContain('unused');
});
});
Loading
Loading