Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1d02681
fix devextreme bundling for strict ESM import rules
GoodDayForSurf Dec 2, 2025
e8545f5
Merge branch '25_2' into 25_2_dx_esm_imports
GoodDayForSurf Dec 2, 2025
22bf32b
fix devextreme bundling for strict ESM import rules
GoodDayForSurf Dec 2, 2025
c58e5c1
Merge branch '25_2_dx_esm_imports' of https://github.com/GoodDayForSu…
GoodDayForSurf Dec 2, 2025
a37779d
fix devextreme bundling for strict ESM import rules
GoodDayForSurf Dec 2, 2025
18fb4d0
fix devextreme bundling for strict ESM import rules
GoodDayForSurf Dec 2, 2025
bfaa62f
Merge branch '25_2' into 25_2_dx_esm_imports
GoodDayForSurf Dec 2, 2025
392db1e
WIP. modify building for ESM lib
GoodDayForSurf Dec 9, 2025
e8fdab1
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 15, 2025
5eeb1fa
Merge branch '25_2' of https://github.com/DevExpress/DevExtreme into …
GoodDayForSurf Dec 15, 2025
e6480d6
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 15, 2025
6c03bbb
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 15, 2025
ac9057c
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 15, 2025
1a4207a
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 17, 2025
52067e0
Merge branch '25_2' into 25_2_dx_esm_imports
GoodDayForSurf Dec 17, 2025
bf2e3c7
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 17, 2025
8b19db4
Merge branch '25_2_dx_esm_imports' of https://github.com/GoodDayForSu…
GoodDayForSurf Dec 17, 2025
3d8c3c5
WIP. remake devextreme build to produce ESM lib package
GoodDayForSurf Dec 18, 2025
263d153
fix vue-tsc version
GoodDayForSurf Dec 18, 2025
d93724d
Merge branch '25_2' into 25_2_dx_esm_imports
GoodDayForSurf Dec 18, 2025
0a01eb7
add types path in modules_metadata.json
GoodDayForSurf Dec 18, 2025
6886ca7
Merge branch '25_2_dx_esm_imports' of https://github.com/GoodDayForSu…
GoodDayForSurf Dec 18, 2025
4989715
add types path in modules_metadata.json
GoodDayForSurf Dec 18, 2025
a840eae
fix types in couple Vue demos
GoodDayForSurf Dec 18, 2025
d04fafb
fix types in couple Vue demos
GoodDayForSurf Dec 18, 2025
994be77
remove exports from package.json
GoodDayForSurf Dec 18, 2025
d93323c
Merge branch '25_2' into 25_2_dx_esm_imports_v2
GoodDayForSurf Dec 18, 2025
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
2 changes: 1 addition & 1 deletion apps/demos/Demos/Charts/MultipleAxes/Vue/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down
4 changes: 2 additions & 2 deletions apps/demos/Demos/Diagram/ItemSelection/Vue/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand All @@ -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<string, any>) => text);
if (filteredItems.length > 0) {
selectedItemNames.value = filteredItems.join(', ');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/demos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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');

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;
}
}
}

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';
}
}
};
};

81 changes: 81 additions & 0 deletions packages/devextreme/build/gulp/fix-imports-path.js
Original file line number Diff line number Diff line change
@@ -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 <path-to-folder>');
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)
},
};
8 changes: 7 additions & 1 deletion packages/devextreme/build/gulp/modules_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,8 @@
"name": "ui/widget/template",
"exports": {
"Template": { "path": "ui.template", "exportAs": "type" }
}
},
"types": "./ui/widget/template.d.ts"
},
{
"name": "utils",
Expand Down Expand Up @@ -694,6 +695,11 @@
"default": { "path": "viz.dxCircularGauge", "isWidget": true }
}
},
{
"name": "viz/common",
"exports": {},
"types": "./viz/common.d.ts"
},
{
"name": "viz/export",
"exports": {
Expand Down
86 changes: 85 additions & 1 deletion packages/devextreme/build/gulp/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ 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');
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;

Expand Down Expand Up @@ -150,6 +153,59 @@ 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)) {
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 = path.join(currentDir, typesFile)
.replace(/\\/g, '/')
.replace(/^.*\/devextreme\//, './');
}

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
Expand All @@ -164,6 +220,33 @@ gulp.task('npm-dist', () => gulp
.pipe(gulp.dest(distPath))
);

gulp.task('add-exports-to-package-json', () => gulp
.src(`${packagePath}/package.json`)
.pipe(
through.obj((file, enc, callback) => {
const pkg = JSON.parse(file.contents.toString(enc));

/* pkg.exports = {
"./dist/!*":"./dist/!*",
...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);
})
)
.pipe(gulp.dest(packagePath))
);

const scssDir = `${packagePath}/scss`;

gulp.task('npm-sass', gulp.series(
Expand All @@ -183,4 +266,5 @@ 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', 'ts-check-public-modules', 'npm-sass', 'add-exports-to-package-json'));

2 changes: 1 addition & 1 deletion packages/devextreme/build/gulp/side-effects-finder.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
11 changes: 7 additions & 4 deletions packages/devextreme/build/gulp/transpile-config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const addImportExtensions = require('./babel-plugin-add-import-extensions');

const common = {
plugins: [
['babel-plugin-inferno', { 'imports': true }],
Expand Down Expand Up @@ -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
}]]
)
}]
])
})
};
Loading
Loading