From 1d02681c114fc83177e6c446527128e6189d268f Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Tue, 2 Dec 2025 10:57:27 +0100 Subject: [PATCH 01/18] fix devextreme bundling for strict ESM import rules --- packages/devextreme/build/gulp/transpile.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/devextreme/build/gulp/transpile.js b/packages/devextreme/build/gulp/transpile.js index f394c310bcea..524e85141590 100644 --- a/packages/devextreme/build/gulp/transpile.js +++ b/packages/devextreme/build/gulp/transpile.js @@ -100,12 +100,19 @@ const createModuleConfig = (name, dir, filePath, dist) => { sideEffects: sideEffectFiles.length ? sideEffectFiles : false, main: normalize(cjsFile), module: normalize(esmFile), + exports: { + ".": { + "import": normalize(esmFile), + "require": normalize(cjsFile), + } + } }; if(hasDTS) { const typingFile = name.replace(/\.js$/, '.d.ts'); result['typings'] = `${isIndex ? './' : '../'}${typingFile}`; + result.exports['types'] = `${isIndex ? './' : '../'}${typingFile}`; } return JSON.stringify(result, null, 2); From 22bf32b06f7ba0222ce20ce0d340c3dba5ede349 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Tue, 2 Dec 2025 16:29:03 +0100 Subject: [PATCH 02/18] fix devextreme bundling for strict ESM import rules --- packages/devextreme/build/gulp/npm.js | 15 ++++++++++++++- packages/devextreme/build/gulp/transpile.js | 7 ------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 2ad26904ec99..89795de5e07b 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -57,7 +57,7 @@ const distGlobsPattern = (jsFolder, exclude) => [ `!${jsFolder}/cldr*`, `!${jsFolder}/globalize/*.*`, `!${jsFolder}/globalize*`, - `!${jsFolder}/exceljs*`, + `!${jsFolder}/dx-exceljs-fork*`, `!${jsFolder}/file-saver*`, `!${jsFolder}/jquery*`, `!${jsFolder}/jspdf*`, @@ -128,6 +128,19 @@ const sources = (src, dist, distGlob) => (() => merge( delete pkg.publishConfig; delete pkg.scripts; + pkg.exports = { + "./common": { + "import": "./esm/common.js", + "require": "./cjs/common.js", + "types": "./common.d.ts" + }, + "./common/ai-integration": { + "import": "./esm/common/ai-integration.js", + "require": "./cjs/common/ai-integration.js", + "types": "./common/ai-integration.d.ts" + } + } + file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); callback(null, file); }) diff --git a/packages/devextreme/build/gulp/transpile.js b/packages/devextreme/build/gulp/transpile.js index 524e85141590..f394c310bcea 100644 --- a/packages/devextreme/build/gulp/transpile.js +++ b/packages/devextreme/build/gulp/transpile.js @@ -100,19 +100,12 @@ const createModuleConfig = (name, dir, filePath, dist) => { sideEffects: sideEffectFiles.length ? sideEffectFiles : false, main: normalize(cjsFile), module: normalize(esmFile), - exports: { - ".": { - "import": normalize(esmFile), - "require": normalize(cjsFile), - } - } }; if(hasDTS) { const typingFile = name.replace(/\.js$/, '.d.ts'); result['typings'] = `${isIndex ? './' : '../'}${typingFile}`; - result.exports['types'] = `${isIndex ? './' : '../'}${typingFile}`; } return JSON.stringify(result, null, 2); From a37779d4d8881da978c635fa19357255381b9691 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Tue, 2 Dec 2025 16:47:33 +0100 Subject: [PATCH 03/18] fix devextreme bundling for strict ESM import rules --- packages/devextreme/build/gulp/npm.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 89795de5e07b..dcb566c0b5ad 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -129,16 +129,16 @@ const sources = (src, dist, distGlob) => (() => merge( delete pkg.scripts; pkg.exports = { - "./common": { - "import": "./esm/common.js", - "require": "./cjs/common.js", - "types": "./common.d.ts" + "./common/*": { + "import": "./esm/*.js", + "require": "./cjs/*.js", + "types": "./*.d.ts" + }, + "./core/utils/*": { + "import": "./esm/*.js", + "require": "./cjs/*.js", + "types": "./*.d.ts" }, - "./common/ai-integration": { - "import": "./esm/common/ai-integration.js", - "require": "./cjs/common/ai-integration.js", - "types": "./common/ai-integration.d.ts" - } } file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); From 18fb4d0667db4de3f7f4dbada90f36928f0e22fd Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Tue, 2 Dec 2025 16:50:00 +0100 Subject: [PATCH 04/18] fix devextreme bundling for strict ESM import rules --- packages/devextreme/build/gulp/npm.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index dcb566c0b5ad..f15e4b839045 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -129,12 +129,7 @@ const sources = (src, dist, distGlob) => (() => merge( delete pkg.scripts; pkg.exports = { - "./common/*": { - "import": "./esm/*.js", - "require": "./cjs/*.js", - "types": "./*.d.ts" - }, - "./core/utils/*": { + "./*": { "import": "./esm/*.js", "require": "./cjs/*.js", "types": "./*.d.ts" From 392db1e48cbb1c6ecc20331bf028b0220fc8de83 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Tue, 9 Dec 2025 11:25:11 +0100 Subject: [PATCH 05/18] WIP. modify building for ESM lib --- packages/devextreme/build/gulp/npm.js | 79 ++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index f15e4b839045..33c08020efd0 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -18,6 +18,8 @@ const env = require('./env-variables.js'); const dataUri = require('./gulp-data-uri').gulpPipe; const headerPipes = require('./header-pipes.js'); const { packageDir, packageDistDir, isEsmPackage, stringSrc, devextremeDistDir } = require('./utils'); +const path = require('path'); +const fs = require('fs'); const resultPath = ctx.RESULT_NPM_PATH; @@ -128,14 +130,6 @@ const sources = (src, dist, distGlob) => (() => merge( delete pkg.publishConfig; delete pkg.scripts; - pkg.exports = { - "./*": { - "import": "./esm/*.js", - "require": "./cjs/*.js", - "types": "./*.d.ts" - }, - } - file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); callback(null, file); }) @@ -158,6 +152,58 @@ const sources = (src, dist, distGlob) => (() => merge( const packagePath = `${resultPath}/${packageDir}`; const distPath = `${resultPath}/${packageDistDir}`; +function collectExports(baseDir) { + const exportsMap = {}; + + function getPath(p) { + return path.posix.join(p.replace(/\\/g, '/')) + .replace(/^.+\/esm\//, './esm/') + .replace(/^.+\/cjs\//, './cjs/') + } + + function walk(currentDir, relativePath = '.') { + const packageJsonPath = path.join(currentDir, 'package.json'); + + if (fs.existsSync(packageJsonPath) && !/(cjs|esm)$/.test(currentDir)) { + console.log('----packageJsonPath------>',currentDir) + try { + const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + const exportEntry = {}; + + if (pkg.module) { + exportEntry.import = getPath(pkg.module); + } + if (pkg.main) { + exportEntry.require = getPath(pkg.main); + } + if (pkg.typings || pkg.types) { + const typesFile = pkg.typings || pkg.types; + // exportEntry.types = getPath(typesFile); + } + + if (Object.keys(exportEntry).length > 0) { + const exportKey = relativePath === '.' ? '.' : `./${relativePath.replace(/\\/g, '/')}`; + exportsMap[exportKey] = exportEntry; + } + } catch (err) { + console.warn(`Failed to read package.json in ${packageJsonPath}:`, err.message); + } + } + + // проход по вложенным папкам + const entries = fs.readdirSync(currentDir, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.isDirectory()) { + walk(path.join(currentDir, entry.name), path.join(relativePath, entry.name)); + } + } + } + + walk(baseDir); + return exportsMap; +} + gulp.task('npm-sources', gulp.series( 'ts-sources', () => gulp @@ -172,6 +218,21 @@ gulp.task('npm-dist', () => gulp .pipe(gulp.dest(distPath)) ); +gulp.task('patch-as-esm-lib', () => gulp + .src(`${resultPath}/${devextremeDistDir}/package.json`) + .pipe( + through.obj((file, enc, callback) => { + const pkg = JSON.parse(file.contents.toString(enc)); + + pkg.exports = collectExports(path.resolve(packagePath)); + console.log('-----+++++++++----->',packageDistDir); + file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); + callback(null, file); + }) + ) + .pipe(gulp.dest(distPath)) +); + const scssDir = `${packagePath}/scss`; gulp.task('npm-sass', gulp.series( @@ -191,4 +252,4 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist', 'ts-check-public-modules', 'npm-sass')); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'ts-check-public-modules', 'npm-sass')); From e8fdab129974c112ca0d9c5e2753fe47265368b2 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Mon, 15 Dec 2025 21:40:59 +0100 Subject: [PATCH 06/18] WIP. remake devextreme build to produce ESM lib package --- .../devextreme/build/gulp/fix-imports-path.js | 81 +++++++++++++++++++ packages/devextreme/build/gulp/npm.js | 14 +++- 2 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 packages/devextreme/build/gulp/fix-imports-path.js diff --git a/packages/devextreme/build/gulp/fix-imports-path.js b/packages/devextreme/build/gulp/fix-imports-path.js new file mode 100644 index 000000000000..b0e55927b4cc --- /dev/null +++ b/packages/devextreme/build/gulp/fix-imports-path.js @@ -0,0 +1,81 @@ +// fix-imports.js +const fs = require('fs'); +const path = require('path'); + +const ROOT_DIR = process.argv[2]; // Папка передаётся первым аргументом + +if (!ROOT_DIR) { + console.error('Использование: node fix-imports.js '); + process.exit(1); +} + +function walkDir(dir, callback) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walkDir(fullPath, callback); + } else if (entry.isFile() && fullPath.endsWith('.js')) { + callback(fullPath); + } + } +} + +function resolveImport(fileDir, importSpecifier) { + const basePath = path.resolve(fileDir, importSpecifier); + + const candidates = [ + basePath + '.js', + path.join(basePath, 'index.js'), + ]; + + for (const full of candidates) { + if (fs.existsSync(full) && fs.statSync(full).isFile()) { + let rel = path.relative(fileDir, full).replace(/\\/g, '/'); + if (!rel.startsWith('.')) { + rel = './' + rel; + } + return rel; + } + } + return null; +} + +function processFile(filePath) { + const original = fs.readFileSync(filePath, 'utf8'); + let content = original; + const fileDir = path.dirname(filePath); + + const importExportRegex = + /(?:import|export)\s+(?:[^'"]*?\s+from\s+)?(['"])(\.{1,2}\/[^'"]*)\1/g; + + const requireRegex = + /require\(\s*(['"])(\.{1,2}\/[^'"]*)\1\s*\)/g; + + function replaceCallback(_, quote, spec) { + // Если уже есть .js или .mjs — не трогаем + if (spec.endsWith('.js') || spec.endsWith('.mjs')) { + return _; + } + + const resolved = resolveImport(fileDir, spec); + if (!resolved) return _; + + return _.replace(spec, resolved); + } + + content = content.replace(importExportRegex, replaceCallback); + content = content.replace(requireRegex, replaceCallback); + + if (content !== original) { + fs.writeFileSync(filePath, content, 'utf8'); + console.log('Updated:', filePath); + } +} + +; + +module.exports = { + addExtensionToImportsPath: function (dir) { + walkDir(path.resolve(dir), processFile) + }, +}; diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 33c08020efd0..5d7372421b67 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -15,6 +15,7 @@ const gulpRename = require('gulp-rename'); const compressionPipes = require('./compression-pipes.js'); const ctx = require('./context.js'); const env = require('./env-variables.js'); +const fixImports = require('./fix-imports-path'); const dataUri = require('./gulp-data-uri').gulpPipe; const headerPipes = require('./header-pipes.js'); const { packageDir, packageDistDir, isEsmPackage, stringSrc, devextremeDistDir } = require('./utils'); @@ -219,20 +220,24 @@ gulp.task('npm-dist', () => gulp ); gulp.task('patch-as-esm-lib', () => gulp - .src(`${resultPath}/${devextremeDistDir}/package.json`) + .src(`${packagePath}/package.json`) .pipe( through.obj((file, enc, callback) => { const pkg = JSON.parse(file.contents.toString(enc)); pkg.exports = collectExports(path.resolve(packagePath)); - console.log('-----+++++++++----->',packageDistDir); file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); callback(null, file); }) ) - .pipe(gulp.dest(distPath)) + .pipe(gulp.dest(packagePath)) ); +gulp.task('fix-ext-in-imports', function(done) { + fixImports.addExtensionToImportsPath(`${packagePath}/esm`); + done(); +}); + const scssDir = `${packagePath}/scss`; gulp.task('npm-sass', gulp.series( @@ -252,4 +257,5 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'ts-check-public-modules', 'npm-sass')); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'fix-ext-in-imports', 'ts-check-public-modules', 'npm-sass')); + From e6480d6f5284e90e7c40afaab0618c66a0e172ef Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Mon, 15 Dec 2025 22:31:07 +0100 Subject: [PATCH 07/18] WIP. remake devextreme build to produce ESM lib package --- packages/devextreme/build/gulp/npm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 5d7372421b67..b36010640a8d 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -257,5 +257,5 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'fix-ext-in-imports', 'ts-check-public-modules', 'npm-sass')); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'npm-sass', 'fix-ext-in-imports', 'ts-check-public-modules')); From 6c03bbb75bceb6c78542793281d7c76365480644 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Mon, 15 Dec 2025 23:14:35 +0100 Subject: [PATCH 08/18] WIP. remake devextreme build to produce ESM lib package --- packages/devextreme/build/gulp/npm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index b36010640a8d..ae39a1887b43 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -257,5 +257,5 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'npm-sass', 'fix-ext-in-imports', 'ts-check-public-modules')); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'npm-sass'/*, 'fix-ext-in-imports', 'ts-check-public-modules'*/)); From ac9057c8f619eabb68513ef569da3f4b51195d37 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Mon, 15 Dec 2025 23:44:39 +0100 Subject: [PATCH 09/18] WIP. remake devextreme build to produce ESM lib package --- packages/devextreme/build/gulp/npm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index ae39a1887b43..4ec0f185d674 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -257,5 +257,5 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist','patch-as-esm-lib', 'npm-sass'/*, 'fix-ext-in-imports', 'ts-check-public-modules'*/)); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist', 'ts-check-public-modules', 'npm-sass'/*, ''patch-as-esm-lib', fix-ext-in-imports'*/)); From 1a4207a2256395c931df81f2e1768f00826534ce Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Wed, 17 Dec 2025 23:11:27 +0100 Subject: [PATCH 10/18] WIP. remake devextreme build to produce ESM lib package --- .../babel-plugin-add-import-extensions.js | 70 +++++++++++++++++++ packages/devextreme/build/gulp/npm.js | 11 +-- .../build/gulp/side-effects-finder.js | 2 +- .../devextreme/build/gulp/transpile-config.js | 11 +-- 4 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js diff --git a/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js b/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js new file mode 100644 index 000000000000..026718a1a6f0 --- /dev/null +++ b/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js @@ -0,0 +1,70 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const TS_OUTPUT_BASE_DIR = 'artifacts/dist_ts'; + +module.exports = function addImportExtensions() { + return { + name: 'add-import-extensions', + visitor: { + 'ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration'(astPath) { + const source = astPath.node.source; + + if (!source) return; + + const value = source.value; + + if (!value || (!value.startsWith('./') && !value.startsWith('../'))) { + return; + } + + if (value.match(/\.(js|mjs|json|css)$/)) { + return; + } + + if (value.endsWith('/')) { + source.value = value + 'index.js'; + return; + } + + const currentFile = astPath.hub?.file?.opts?.filename; + const distPathRegExp = new RegExp(TS_OUTPUT_BASE_DIR) + + if (currentFile) { + const currentDir = path.dirname(currentFile); + const resolvedPath = path.resolve(currentDir, value).replace(distPathRegExp,'js'); + + let jsFilePath = resolvedPath + '.js'; + + if ( fs.existsSync(jsFilePath) + || fs.existsSync(jsFilePath = resolvedPath + '.ts') + ) { + const stat = fs.statSync(jsFilePath); + + if (stat.isFile()) { + source.value = value + '.js'; + return; + } + } + + if (fs.existsSync(resolvedPath)) { + const stat = fs.statSync(resolvedPath); + + if (stat.isDirectory()) { + const indexPath = path.join(resolvedPath, 'index.js'); + + if (fs.existsSync(indexPath)) { + source.value = value + '/index.js'; + return; + } + } + } + } + + source.value = value + '.js'; + } + } + }; +}; + diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 4ec0f185d674..7b85118e2300 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -15,7 +15,6 @@ const gulpRename = require('gulp-rename'); const compressionPipes = require('./compression-pipes.js'); const ctx = require('./context.js'); const env = require('./env-variables.js'); -const fixImports = require('./fix-imports-path'); const dataUri = require('./gulp-data-uri').gulpPipe; const headerPipes = require('./header-pipes.js'); const { packageDir, packageDistDir, isEsmPackage, stringSrc, devextremeDistDir } = require('./utils'); @@ -166,7 +165,6 @@ function collectExports(baseDir) { const packageJsonPath = path.join(currentDir, 'package.json'); if (fs.existsSync(packageJsonPath) && !/(cjs|esm)$/.test(currentDir)) { - console.log('----packageJsonPath------>',currentDir) try { const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); const exportEntry = {}; @@ -219,7 +217,7 @@ gulp.task('npm-dist', () => gulp .pipe(gulp.dest(distPath)) ); -gulp.task('patch-as-esm-lib', () => gulp +gulp.task('add-exports-to-package-json', () => gulp .src(`${packagePath}/package.json`) .pipe( through.obj((file, enc, callback) => { @@ -233,11 +231,6 @@ gulp.task('patch-as-esm-lib', () => gulp .pipe(gulp.dest(packagePath)) ); -gulp.task('fix-ext-in-imports', function(done) { - fixImports.addExtensionToImportsPath(`${packagePath}/esm`); - done(); -}); - const scssDir = `${packagePath}/scss`; gulp.task('npm-sass', gulp.series( @@ -257,5 +250,5 @@ gulp.task('npm-sass', gulp.series( ) )); -gulp.task('npm', gulp.series('npm-sources', 'npm-dist', 'ts-check-public-modules', 'npm-sass'/*, ''patch-as-esm-lib', fix-ext-in-imports'*/)); +gulp.task('npm', gulp.series('npm-sources', 'npm-dist', 'ts-check-public-modules', 'npm-sass', 'add-exports-to-package-json')); diff --git a/packages/devextreme/build/gulp/side-effects-finder.js b/packages/devextreme/build/gulp/side-effects-finder.js index 2df1e4c1ee35..50aa63a2bd82 100644 --- a/packages/devextreme/build/gulp/side-effects-finder.js +++ b/packages/devextreme/build/gulp/side-effects-finder.js @@ -46,7 +46,7 @@ class SideEffectFinder { .forEach((str) => { let importPath = str.match(relativePathRegExp)[0].replace(/(^['"]|['"]$)/g, ''); - importPath = path.join(path.dirname(modulePath), importPath) + '.js'; + importPath = path.join(path.dirname(modulePath), importPath); if(!fs.existsSync(importPath)) { importPath = importPath.replace(/\.js$/, '/index.js'); diff --git a/packages/devextreme/build/gulp/transpile-config.js b/packages/devextreme/build/gulp/transpile-config.js index 9bee0fbd6141..efd7e9aafdd4 100644 --- a/packages/devextreme/build/gulp/transpile-config.js +++ b/packages/devextreme/build/gulp/transpile-config.js @@ -1,5 +1,7 @@ 'use strict'; +const addImportExtensions = require('./babel-plugin-add-import-extensions'); + const common = { plugins: [ ['babel-plugin-inferno', { 'imports': true }], @@ -33,11 +35,12 @@ module.exports = { esm: Object.assign({}, common, { // eslint-disable-next-line spellcheck/spell-checker presets: [['@babel/preset-env', { targets, modules: false }]], - plugins: common.plugins.concat( - [['@babel/plugin-transform-runtime', { + plugins: common.plugins.concat([ + addImportExtensions, + ['@babel/plugin-transform-runtime', { useESModules: true, version: '7.5.0' // https://github.com/babel/babel/issues/10261#issuecomment-514687857 - }]] - ) + }] + ]) }) }; From bf2e3c7a2355f6357c354cb91d2e0e6b10c00d8a Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 00:29:45 +0100 Subject: [PATCH 11/18] WIP. remake devextreme build to produce ESM lib package --- packages/devextreme/build/gulp/npm.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 7b85118e2300..6c8d30b485ef 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -177,7 +177,9 @@ function collectExports(baseDir) { } if (pkg.typings || pkg.types) { const typesFile = pkg.typings || pkg.types; - // exportEntry.types = getPath(typesFile); + exportEntry.types = path.join(currentDir, typesFile) + .replace(/\\/g, '/') + .replace(/^.*\/devextreme\//, './'); } if (Object.keys(exportEntry).length > 0) { @@ -223,8 +225,13 @@ gulp.task('add-exports-to-package-json', () => gulp through.obj((file, enc, callback) => { const pkg = JSON.parse(file.contents.toString(enc)); - pkg.exports = collectExports(path.resolve(packagePath)); + pkg.exports = { + "./dist/*":"./dist/*", + ...collectExports(path.resolve(packagePath)) + }; + file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); + callback(null, file); }) ) From 3d8c3c512f55e98ef591e6335727e7b986417ef1 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 01:05:55 +0100 Subject: [PATCH 12/18] WIP. remake devextreme build to produce ESM lib package --- .../babel-plugin-add-import-extensions.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js b/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js index 026718a1a6f0..03124f1cf8a5 100644 --- a/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js +++ b/packages/devextreme/build/gulp/babel-plugin-add-import-extensions.js @@ -35,19 +35,6 @@ module.exports = function addImportExtensions() { const currentDir = path.dirname(currentFile); const resolvedPath = path.resolve(currentDir, value).replace(distPathRegExp,'js'); - let jsFilePath = resolvedPath + '.js'; - - if ( fs.existsSync(jsFilePath) - || fs.existsSync(jsFilePath = resolvedPath + '.ts') - ) { - const stat = fs.statSync(jsFilePath); - - if (stat.isFile()) { - source.value = value + '.js'; - return; - } - } - if (fs.existsSync(resolvedPath)) { const stat = fs.statSync(resolvedPath); @@ -60,6 +47,19 @@ module.exports = function addImportExtensions() { } } } + + let jsFilePath = resolvedPath + '.js'; + + if ( fs.existsSync(jsFilePath) + || fs.existsSync(jsFilePath = resolvedPath + '.ts') + ) { + const stat = fs.statSync(jsFilePath); + + if (stat.isFile()) { + source.value = value + '.js'; + return; + } + } } source.value = value + '.js'; From 263d153fdfa6c5c331eb7fd90b9302fdb8a21f71 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 01:07:25 +0100 Subject: [PATCH 13/18] fix vue-tsc version --- apps/demos/package.json | 2 +- pnpm-lock.yaml | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/demos/package.json b/apps/demos/package.json index 5f68340dc040..b8bb429ef6a5 100644 --- a/apps/demos/package.json +++ b/apps/demos/package.json @@ -152,7 +152,7 @@ "testcafe": "3.7.2", "testcafe-reporter-spec-time": "4.0.0", "ts-node": "10.9.2", - "vue-tsc": "^3.0.6" + "vue-tsc": "3.0.6" }, "scripts": { "test": "jest --coverage --runInBand", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index daccadce83a4..6f5b3013f923 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -696,8 +696,8 @@ importers: specifier: 10.9.2 version: 10.9.2(@swc/core@1.15.3)(@types/node@18.19.64)(typescript@5.9.3) vue-tsc: - specifier: ^3.0.6 - version: 3.0.8(typescript@5.9.3) + specifier: 3.0.6 + version: 3.0.6(typescript@5.9.3) apps/react: dependencies: @@ -8485,8 +8485,8 @@ packages: typescript: optional: true - '@vue/language-core@3.0.8': - resolution: {integrity: sha512-eYs6PF7bxoPYvek9qxceo1BCwFbJZYqJll+WaYC8o8ec60exqj+n+QRGGiJHSeUfYp0hDxARbMdxMq/fbPgU5g==} + '@vue/language-core@3.0.6': + resolution: {integrity: sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -19617,8 +19617,8 @@ packages: peerDependencies: vue: ^3.2.0 - vue-tsc@3.0.8: - resolution: {integrity: sha512-H9yg/m6ywykmWS+pIAEs65v2FrVm5uOA0a0dHkX6Sx8dNg1a1m4iudt/6eGa9fAenmNHGlLFN9XpWQb8i5sU1w==} + vue-tsc@3.0.6: + resolution: {integrity: sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -24326,7 +24326,7 @@ snapshots: '@babel/types@7.27.1': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/types@7.28.5': dependencies: @@ -29308,7 +29308,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/language-core@3.0.8(typescript@5.9.3)': + '@vue/language-core@3.0.6(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 '@vue/compiler-dom': 3.5.13 @@ -29317,7 +29317,7 @@ snapshots: alien-signals: 2.0.7 muggle-string: 0.4.1 path-browserify: 1.0.1 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: typescript: 5.9.3 @@ -34573,9 +34573,9 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.4(picomatch@4.0.2): + fdir@6.4.4(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -43722,8 +43722,8 @@ snapshots: tinyglobby@0.2.13: dependencies: - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.4.4(picomatch@4.0.3) + picomatch: 4.0.3 tinyglobby@0.2.15: dependencies: @@ -44949,10 +44949,10 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.8.3) - vue-tsc@3.0.8(typescript@5.9.3): + vue-tsc@3.0.6(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.23 - '@vue/language-core': 3.0.8(typescript@5.9.3) + '@vue/language-core': 3.0.6(typescript@5.9.3) typescript: 5.9.3 vue@3.2.47: From 0a01eb7d6b9351870d9887e937eadd8ef2d818bb Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 16:17:28 +0100 Subject: [PATCH 14/18] add types path in modules_metadata.json --- packages/devextreme/build/gulp/modules_metadata.json | 7 ++++++- packages/devextreme/build/gulp/npm.js | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/devextreme/build/gulp/modules_metadata.json b/packages/devextreme/build/gulp/modules_metadata.json index 4bba72e98a25..0b97f5b6f04a 100644 --- a/packages/devextreme/build/gulp/modules_metadata.json +++ b/packages/devextreme/build/gulp/modules_metadata.json @@ -661,7 +661,8 @@ "name": "ui/widget/template", "exports": { "Template": { "path": "ui.template", "exportAs": "type" } - } + }, + "types": "./ui/widget/template.d.ts" }, { "name": "utils", @@ -694,6 +695,10 @@ "default": { "path": "viz.dxCircularGauge", "isWidget": true } } }, + { + "name": "viz/common", + "types": "./viz/common.d.ts" + }, { "name": "viz/export", "exports": { diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index 6c8d30b485ef..cc7fd355c0aa 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -11,6 +11,7 @@ const replace = require('gulp-replace'); const lazyPipe = require('lazypipe'); const gulpFilter = require('gulp-filter'); const gulpRename = require('gulp-rename'); +const MODULES = require('./modules_metadata.json'); const compressionPipes = require('./compression-pipes.js'); const ctx = require('./context.js'); @@ -230,6 +231,14 @@ gulp.task('add-exports-to-package-json', () => gulp ...collectExports(path.resolve(packagePath)) }; + MODULES.forEach((item) => { + const exportPath = './' + item.name; + if(item.types && !pkg.exports[exportPath]?.types) { + pkg.exports[exportPath] = pkg.exports[exportPath] || {}; + pkg.exports[exportPath].types = item.types; + } + }) + file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); callback(null, file); From 4989715c03688ba8293965b34f36d7b99aaeca9a Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 16:40:10 +0100 Subject: [PATCH 15/18] add types path in modules_metadata.json --- packages/devextreme/build/gulp/modules_metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/devextreme/build/gulp/modules_metadata.json b/packages/devextreme/build/gulp/modules_metadata.json index 0b97f5b6f04a..a25c44c91eaa 100644 --- a/packages/devextreme/build/gulp/modules_metadata.json +++ b/packages/devextreme/build/gulp/modules_metadata.json @@ -697,6 +697,7 @@ }, { "name": "viz/common", + "exports": {}, "types": "./viz/common.d.ts" }, { From a840eae0599bb77eacda86ecdc38c536874df3d4 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 17:33:39 +0100 Subject: [PATCH 16/18] fix types in couple Vue demos --- apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue | 2 +- apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue b/apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue index 65d5d0ba4d27..31e03cbb1fab 100644 --- a/apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue +++ b/apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue @@ -70,7 +70,7 @@ function customizeTooltip(pointInfo: DxChartTypes.PointInfo) { const items = pointInfo.valueText?.split('\n'); const color = pointInfo.point?.getColor(); - items?.forEach((item, index) => { + items?.forEach((item: string, index: number) => { if (item.indexOf(pointInfo.seriesName) === 0) { const element = document.createElement('span'); diff --git a/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue b/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue index 2f9587c008ef..b1eb639b96e5 100644 --- a/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue +++ b/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue @@ -46,7 +46,7 @@ const textExpression = 'Full_Name'; function onContentReady(e: DxDiagramTypes.ContentReadyEvent) { const diagram = e.component; // preselect some shape - const items = diagram.getItems().filter(({ itemType, dataItem }) => itemType === 'shape' && (dataItem[textExpression] === 'Greta Sims')); + const items = diagram.getItems().filter(({ itemType, dataItem }: DxDiagramTypes.Item) => itemType === 'shape' && (dataItem[textExpression] === 'Greta Sims')); if (items.length > 0) { diagram.setSelectedItems(items); diagram.scrollToItem(items[0]); From d04fafb8ee46799f2e37fe979c5a52daf44c1623 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 18:01:03 +0100 Subject: [PATCH 17/18] fix types in couple Vue demos --- apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue | 2 +- .../TreeView/DragAndDropHierarchicalDataStructure/Vue/App.vue | 4 ++-- .../Demos/TreeView/DragAndDropPlainDataStructure/Vue/App.vue | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue b/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue index b1eb639b96e5..0c271828b571 100644 --- a/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue +++ b/apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue @@ -56,7 +56,7 @@ function onContentReady(e: DxDiagramTypes.ContentReadyEvent) { function onSelectionChanged({ items }: DxDiagramTypes.SelectionChangedEvent) { selectedItemNames.value = 'Nobody has been selected'; const filteredItems = items - .filter((item) => item.itemType === 'shape') + .filter((item: DxDiagramTypes.Item) => item.itemType === 'shape') .map(({ text }: Record) => text); if (filteredItems.length > 0) { selectedItemNames.value = filteredItems.join(', '); diff --git a/apps/demos/Demos/TreeView/DragAndDropHierarchicalDataStructure/Vue/App.vue b/apps/demos/Demos/TreeView/DragAndDropHierarchicalDataStructure/Vue/App.vue index d76877e5223c..57c1c3ab6a62 100644 --- a/apps/demos/Demos/TreeView/DragAndDropHierarchicalDataStructure/Vue/App.vue +++ b/apps/demos/Demos/TreeView/DragAndDropHierarchicalDataStructure/Vue/App.vue @@ -167,7 +167,7 @@ function moveNode( ) { const fromNodeContainingArray = getNodeContainingArray(fromNode, fromItems); const fromIndex = fromNodeContainingArray - ?.findIndex((item) => item.id === fromNode.itemData?.id) || -1; + ?.findIndex((item: DriveItem) => item.id === fromNode.itemData?.id) || -1; if (fromIndex !== -1 && fromNodeContainingArray) { fromNodeContainingArray.splice(fromIndex, 1); @@ -179,7 +179,7 @@ function moveNode( const toNodeContainingArray = getNodeContainingArray(toNode, toItems); const toIndex = toNode === null ? toNodeContainingArray?.length || 0 - : toNodeContainingArray?.findIndex((item) => item.id === toNode.itemData?.id) || 0; + : toNodeContainingArray?.findIndex((item: DriveItem) => item.id === toNode.itemData?.id) || 0; toNodeContainingArray?.splice(toIndex, 0, fromNode.itemData); } } diff --git a/apps/demos/Demos/TreeView/DragAndDropPlainDataStructure/Vue/App.vue b/apps/demos/Demos/TreeView/DragAndDropPlainDataStructure/Vue/App.vue index ca750ebcae7c..8e3c4fce7fa1 100644 --- a/apps/demos/Demos/TreeView/DragAndDropPlainDataStructure/Vue/App.vue +++ b/apps/demos/Demos/TreeView/DragAndDropPlainDataStructure/Vue/App.vue @@ -184,7 +184,7 @@ function moveChildren(node: Node, fromDataSource: DriveItem[], toDataSource: any return; } - node.children?.forEach((child) => { + node.children?.forEach((child: Node) => { if (child.itemData?.isDirectory) { moveChildren(child, fromDataSource, toDataSource); } From 994be7721552bc81555e4b12be341d35ccbe894c Mon Sep 17 00:00:00 2001 From: Aliullov Vlad Date: Thu, 18 Dec 2025 22:09:10 +0100 Subject: [PATCH 18/18] remove exports from package.json --- packages/devextreme/build/gulp/npm.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/devextreme/build/gulp/npm.js b/packages/devextreme/build/gulp/npm.js index cc7fd355c0aa..c30ddb147076 100644 --- a/packages/devextreme/build/gulp/npm.js +++ b/packages/devextreme/build/gulp/npm.js @@ -226,8 +226,8 @@ gulp.task('add-exports-to-package-json', () => gulp through.obj((file, enc, callback) => { const pkg = JSON.parse(file.contents.toString(enc)); - pkg.exports = { - "./dist/*":"./dist/*", +/* pkg.exports = { + "./dist/!*":"./dist/!*", ...collectExports(path.resolve(packagePath)) }; @@ -237,7 +237,7 @@ gulp.task('add-exports-to-package-json', () => gulp pkg.exports[exportPath] = pkg.exports[exportPath] || {}; pkg.exports[exportPath].types = item.types; } - }) + })*/ file.contents = Buffer.from(JSON.stringify(pkg, null, 2));