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
26 changes: 17 additions & 9 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pnpm install --frozen-lockfile
devextreme-metadata/ # Metadata generation for wrappers
devextreme-monorepo-tools/ # Internal tooling
nx-infra-plugin/ # Custom Nx executors for build automation
workflows/ # Reusable CI/CD workflow configurations
workflows/ # Cross-package NX build orchestration (all:build-dev, all:build-testing)
testcafe-models/ # TestCafe page object models

/apps/
Expand Down Expand Up @@ -154,7 +154,7 @@ pnpm run clean
**Build process includes:**
1. Localization generation (via `devextreme-nx-infra-plugin:localization` executor)
2. Component generation (Renovation architecture)
3. Transpilation (Babel)
3. Transpilation (via native NX executors: `babel-transform` for JS, `build-typescript` for TS)
4. Bundle creation (Webpack) - `bundle:debug` and `bundle:prod` targets
5. TypeScript declarations - `build:declarations` target
6. SCSS compilation (from devextreme-scss)
Expand Down Expand Up @@ -186,13 +186,21 @@ The `packages/nx-infra-plugin` provides custom Nx executors for build automation

| Executor | Description |
|----------|-------------|
| `localization` | Generates localization message files and TypeScript CLDR data modules |
| `add-license-headers` | Adds license headers to source files |
| `copy-files` | Copies files with glob pattern support |
| `clean` | Cleans directories with exclude pattern support |
| `build-typescript` | Builds TypeScript projects |
| `generate-components` | Generates Angular/React/Vue wrapper components |
| `karma-multi-env` | Runs Karma tests across multiple Angular environments |
| `add-license-headers` | Adds DevExtreme license headers to compiled files with version information |
| `babel-transform` | Transforms JS/TS files using Babel with configurable presets, debug block removal, and extension renaming |
| `build-angular-library` | Builds Angular libraries using ng-packagr programmatically |
| `build-typescript` | Compiles TypeScript to CJS or ESM modules with configurable output format, tsconfig, and path alias resolution |
| `clean` | Removes directories and files with support for exclusion patterns |
| `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 |
| `generate-component-names` | Generates TypeScript file with component name constants for test automation |
| `generate-components` | Generates framework components (React/Vue/Angular) from DevExtreme metadata |
| `karma-multi-env` | Runs Karma tests across multiple Angular environments (client, server, hydration) |
| `localization` | Generates CLDR data and compiles localization message files from JSON to JavaScript |
| `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 |

**Example executor usage in project.json:**
```json
Expand Down
76 changes: 0 additions & 76 deletions packages/devextreme/build/gulp/side-effects-finder.js

This file was deleted.

110 changes: 0 additions & 110 deletions packages/devextreme/build/gulp/transpile.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,25 @@
'use strict';

const babel = require('gulp-babel');
const flatMap = require('gulp-flatmap');
const fs = require('fs');
const gulp = require('gulp');

const normalize = require('normalize-path');
const notify = require('gulp-notify');
const path = require('path');
const plumber = require('gulp-plumber');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const watch = require('gulp-watch');

const removeDebug = require('./compression-pipes.js').removeDebug;
const ctx = require('./context.js');
const testsConfig = require('../../testing/tests.babelrc.json');
const transpileConfig = require('./transpile-config');

const createTsCompiler = require('./typescript/compiler');

const { SideEffectFinder } = require('./side-effects-finder');

const sideEffectFinder = new SideEffectFinder();
const src = [
'js/**/*.*',
'!js/**/*.d.ts',
'!js/**/*.{tsx,ts}',
'!js/__internal/**/*.*',
];

const esmTranspileSrc = src.concat([
'!js/viz/docs/**/*',
'!**/*.json'
]);

const srcTsPattern = 'js/__internal/**/*.{ts,tsx}';
const srcTsIgnorePatterns = [
'**/__tests__/**/*'
];

const srcDir = path.join(process.cwd(), './js');
const generatedTs = [
'events/click.d.ts',
'events/contextmenu.d.ts',
'events/dblclick.d.ts',
'events/drag.d.ts',
'events/hold.d.ts',
'events/hover.d.ts',
'events/pointer.d.ts',
'events/swipe.d.ts',
'events/transform.d.ts',
'integration/jquery.d.ts'
];

const TS_OUTPUT_BASE_DIR = 'artifacts/dist_ts';
const TS_COMPILER_CONFIG = {
baseAbsPath: path.resolve(__dirname, '../..'),
Expand All @@ -70,82 +36,6 @@ const TS_COMPILER_CONFIG = {
},
};

const createModuleConfig = (name, dir, filePath, dist) => {
const isIndex = name === 'index.js';
const relative = path.join('./', dir.replace(srcDir, ''), name);
const currentPath = isIndex ? path.join(relative, '../') : relative;
const esmFile = path.relative(currentPath, path.join('./esm', relative));
const esmFilePath = path.join(dist, './esm', dir.replace(srcDir, ''), name);
const cjsFile = path.relative(currentPath, path.join('./cjs', relative));
const hasRealDTS = fs.existsSync(filePath.replace(/\.js$/, '.d.ts'));
const hasGeneratedDTS = generatedTs.indexOf(relative.replace(/\.js$/, '.d.ts')) !== -1;
const hasDTS = hasRealDTS || hasGeneratedDTS;
const relativeEsmBase = normalize(esmFile).match(/^.*\/esm\//)[0];
const sideEffectFiles = sideEffectFinder.getModuleSideEffectFiles(esmFilePath)
.map((importPath) => importPath.replace(/^.*\/esm\//, relativeEsmBase));

const result = {
sideEffects: sideEffectFiles.length ? sideEffectFiles : false,
main: normalize(cjsFile),
module: normalize(esmFile),
};

if(hasDTS) {
const typingFile = name.replace(/\.js$/, '.d.ts');

result['typings'] = `${isIndex ? './' : '../'}${typingFile}`;
}

return JSON.stringify(result, null, 2);
};

const transpileTs = (compiler, src) => {
const task = () => compiler
.compileTs(src, srcTsIgnorePatterns)
.pipe(gulp.dest(TS_OUTPUT_BASE_DIR));

task.displayName = 'transpile TS';
return task;
};

gulp.task('ts-compile-internal', (done) => {
createTsCompiler(TS_COMPILER_CONFIG).then((compiler) => {
transpileTs(compiler, srcTsPattern)()
.on('end', done)
.on('error', done);
});
});

gulp.task('esm-dual-mode-manifests', () => {
const dist = ctx.TRANSPILED_PROD_ESM_PATH;
return gulp
.src(esmTranspileSrc)
.pipe(flatMap((stream, file) => {
const filePath = file.path;
const parsedPath = path.parse(filePath);
const fileName = parsedPath.base;
const fileDir = parsedPath.dir;

// NOTE: flatmap thinks that the 'js/viz/vector_map.utils' folder is a file.
if(file.extname === '.utils') return stream;

return stream
.pipe(replace(/[\s\S]*/, createModuleConfig(fileName, fileDir, filePath, dist)))
.pipe(rename(fPath => {
const isIndexFile = parsedPath.base === 'index.js';
const shouldBePlacedInSeparateDir = !isIndexFile;

if(shouldBePlacedInSeparateDir) {
fPath.dirname = path.join(fPath.dirname, fPath.basename);
}

fPath.basename = 'package';
fPath.extname = '.json';
}));
}))
.pipe(gulp.dest(dist));
});

const watchJsTask = () => {
const watchTask = watch(src)
.on('ready', () => console.log('transpile JS is watching for changes...'))
Expand Down
51 changes: 42 additions & 9 deletions packages/devextreme/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,14 @@
}
},
"build:ts:internal": {
"executor": "nx:run-commands",
"executor": "devextreme-nx-infra-plugin:build-typescript",
"options": {
"command": "gulp ts-compile-internal",
"cwd": "{projectRoot}"
"srcPattern": "./js/__internal/**/*.{ts,tsx}",
"excludePatterns": ["./js/__internal/**/__tests__/**/*"],
"tsconfig": "./js/__internal/tsconfig.json",
"outDir": "./artifacts/dist_ts",
"resolvePaths": true,
"resolvePathsBaseDir": "./js"
},
"inputs": [
"{projectRoot}/js/__internal/**/*.{ts,tsx}",
Expand Down Expand Up @@ -175,7 +179,10 @@
"!{projectRoot}/js/**/*.d.ts",
"!{projectRoot}/js/__internal/**/*"
],
"outputs": ["{projectRoot}/artifacts/transpiled"],
"outputs": [
"{projectRoot}/artifacts/transpiled",
"{projectRoot}/artifacts/transpiled-renovation-npm"
],
"cache": true
},
"copy:json:transpiled": {
Expand Down Expand Up @@ -268,7 +275,10 @@
}
},
"inputs": ["{projectRoot}/artifacts/dist_ts/__internal/**/*.{js,jsx}"],
"outputs": ["{projectRoot}/artifacts/transpiled/__internal"],
"outputs": [
"{projectRoot}/artifacts/transpiled/__internal",
"{projectRoot}/artifacts/transpiled-renovation-npm/__internal"
],
"cache": true
},
"build:npm:esm:internal": {
Expand Down Expand Up @@ -317,14 +327,37 @@
}
},
"inputs": ["{projectRoot}/build/bundle-templates/**/*.js"],
"outputs": ["{projectRoot}/artifacts/transpiled/bundles"],
"outputs": [
"{projectRoot}/artifacts/transpiled/bundles",
"{projectRoot}/artifacts/transpiled-renovation-npm/bundles",
"{projectRoot}/artifacts/transpiled-esm-npm/bundles"
],
"cache": true
},
"build:npm:dual-mode": {
"executor": "nx:run-commands",
"executor": "devextreme-nx-infra-plugin:create-dual-mode-manifest",
"options": {
"command": "cross-env BUILD_ESM_PACKAGE=true gulp esm-dual-mode-manifests",
"cwd": "{projectRoot}"
"esmDir": "./artifacts/transpiled-esm-npm/esm",
"cjsDir": "./artifacts/transpiled-esm-npm/cjs",
"outputDir": "./artifacts/transpiled-esm-npm",
"srcDir": "./js",
"excludePatterns": [
"__internal/**/*",
"viz/docs/**/*",
"bundles/**/*"
],
"generatedDtsFiles": [
"events/click.d.ts",
"events/contextmenu.d.ts",
"events/dblclick.d.ts",
"events/drag.d.ts",
"events/hold.d.ts",
"events/hover.d.ts",
"events/pointer.d.ts",
"events/swipe.d.ts",
"events/transform.d.ts",
"integration/jquery.d.ts"
]
},
"inputs": [
"{projectRoot}/artifacts/transpiled-esm-npm/esm/**/*",
Expand Down
5 changes: 5 additions & 0 deletions packages/nx-infra-plugin/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
"implementation": "./src/executors/babel-transform/executor",
"schema": "./src/executors/babel-transform/schema.json",
"description": "Transform JavaScript/TypeScript files using Babel with configurable presets"
},
"create-dual-mode-manifest": {
"implementation": "./src/executors/create-dual-mode-manifest/executor",
"schema": "./src/executors/create-dual-mode-manifest/schema.json",
"description": "Generate package.json files for dual-mode (ESM + CJS) package support"
}
}
}
5 changes: 4 additions & 1 deletion packages/nx-infra-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
"dependencies": {
"fs-extra": "11.2.0",
"glob": "11.1.0",
"minimatch": "9.0.5",
"normalize-path": "3.0.0",
"lodash": "4.17.23",
"rimraf": "3.0.2"
"rimraf": "3.0.2",
"tsc-alias": "1.8.10"
},
"peerDependencies": {
"@babel/core": ">=7.0.0",
Expand Down Expand Up @@ -69,6 +71,7 @@
"@types/normalize-path": "3.0.2",
"@types/node": "18.19.130",
"@types/lodash": "4.17.23",
"@types/minimatch": "5.1.2",
"prettier": "catalog:tools",
"ts-jest": "29.1.3",
"typescript": "4.9.5"
Expand Down
Loading
Loading