diff --git a/packages/devextreme-vue/gulpfile.js b/packages/devextreme-vue/gulpfile.js index 8c4664fb4916..f9ff85b6da07 100644 --- a/packages/devextreme-vue/gulpfile.js +++ b/packages/devextreme-vue/gulpfile.js @@ -5,6 +5,7 @@ const shell = require('gulp-shell'); const header = require('gulp-header'); const ts = require('gulp-typescript'); const config = require('./build.config'); +const path = require('path'); const GENERATE = 'generate'; const CLEAN = 'clean'; @@ -15,6 +16,10 @@ const NPM_LICENSE = 'npm.license'; const ADD_HEADERS = 'npm.license-headers'; const NPM_README = 'npm.readme'; const NPM_BUILD = 'npm.build'; +const NPM_BUILD_ESM = 'npm.build-esm'; +const NPM_BUILD_CJS = 'npm.build-cjs'; +const NPM_PREPARE_MODULES = 'npm.prepare-modules'; +const NPM_PREPARE_FOLDERS = 'npm.prepare-folders'; const NPM_PACK = 'npm.pack'; const VUE_VERSION = 3; @@ -60,18 +65,57 @@ gulp.task(NPM_README, () => gulp.src(config.npm.readme).pipe(gulp.dest(config.npm.dist)) ); +gulp.task(NPM_BUILD_ESM, gulp.series( + () => gulp.src([ + config.src, + `!${config.testSrc}` + ]) + .pipe(ts('tsconfig.esm.json')) + .pipe(gulp.dest(config.npm.dist + '/esm')) +)); + +gulp.task(NPM_BUILD_CJS, gulp.series( + () => gulp.src([ + config.src, + `!${config.testSrc}` + ]) + .pipe(ts('tsconfig.json')) + .pipe(gulp.dest(config.npm.dist + '/cjs')) +)); + gulp.task(NPM_BUILD, gulp.series( - gulp.parallel(NPM_LICENSE, NPM_PACKAGE, NPM_README), - () => { - return gulp.src([ - config.src, - ...config.ignoredGlobs - ]) - .pipe(ts('tsconfig.json')) - .pipe(gulp.dest(config.npm.dist)); - } + gulp.parallel( + NPM_LICENSE, + NPM_PACKAGE, + NPM_README, + NPM_BUILD_ESM, + NPM_BUILD_CJS + ) )); +gulp.task(NPM_PREPARE_MODULES, (done) => { + const modulesIndex = fs.readFileSync(config.npm.dist + 'esm/index.js', 'utf8'); + + [...modulesIndex.matchAll(/from "\.\/([^;]+)";/g)].forEach(([,modulePath]) => { + const moduleName = modulePath.match(/[^/]+$/)[0]; + + makeModuleForFile(moduleName); + }) + + done(); +}); + +gulp.task(NPM_PREPARE_FOLDERS, (done) => { + [ + ['common'], + ['common/data'] + ].forEach( + ([folder, moduleFileName]) => makeModuleForFolder(folder, moduleFileName) + ) + + done(); +}); + gulp.task(ADD_HEADERS, function () { const pkg = require('./package.json'); const now = new Date(); @@ -105,6 +149,68 @@ gulp.task(ADD_HEADERS, function () { gulp.task(NPM_PACK, gulp.series( NPM_CLEAN, NPM_BUILD, + gulp.parallel( + NPM_PREPARE_MODULES, + NPM_PREPARE_FOLDERS, + ), ADD_HEADERS, shell.task(['npm pack'], {cwd: config.npm.dist}) )); + +function makeModuleForFolder(folderPath, moduleFileNames) { + const distFolder = path.join(__dirname, config.npm.dist); + const distEsmFolder = path.join(distFolder, 'esm', folderPath); + const moduleNames = moduleFileNames || findJsModuleFileNamesInFolder(distEsmFolder); + + try { + fs.mkdirSync(path.join(distFolder, folderPath)); + + if (fs.existsSync(path.join(distEsmFolder, 'index.js'))) { + generatePackageJsonFile(folderPath); + } + + moduleNames.forEach((moduleFileName) => { + makeModuleForFile(moduleFileName, folderPath); + }) + } catch (error) { + error.message = `Exception while makeModuleForFolder(${folderPath}).\n ${error.message}`; + throw(error); + } +} + +function makeModuleForFile(moduleFileName, folder = '') { + fs.mkdirSync(path.join(__dirname, config.npm.dist, folder, moduleFileName)); + + generatePackageJsonFile(folder, moduleFileName); +} + +function generatePackageJsonFile(folder, moduleFileName) { + const moduleName = moduleFileName || ''; + const absoluteModulePath = path.join(__dirname, config.npm.dist, folder, moduleName); + const moduleFilePath = (folder ? folder + '/' : '') + (moduleName || 'index'); + const relativePath = path.relative( + absoluteModulePath, + path.join(__dirname, config.npm.dist, 'esm', moduleFilePath + '.js') + ); + + const relativeBase = '../'.repeat(relativePath.split('..').length - 1); + + fs.writeFileSync(path.join(absoluteModulePath , 'package.json'), JSON.stringify({ + sideEffects: false, + main: `${relativeBase}cjs/${moduleFilePath}.js`, + module: `${relativeBase}esm/${moduleFilePath}.js`, + typings: `${relativeBase}cjs/${moduleFilePath}.d.ts`, + }, null, 2)); +} + +function findJsModuleFileNamesInFolder(dir) { + return fs.readdirSync(dir).filter((file) => { + const filePath = path.join(dir, file); + + return !fs.statSync(filePath).isDirectory() + && file.includes('.js') + && !file.includes('index.js') + } + ).map((filePath) => path.parse(filePath).name); +} + diff --git a/packages/devextreme-vue/package.json b/packages/devextreme-vue/package.json index 6d15f0f1609c..b37cf4cb9a36 100644 --- a/packages/devextreme-vue/package.json +++ b/packages/devextreme-vue/package.json @@ -6,8 +6,9 @@ "type": "git", "url": "https://github.com/DevExpress/devextreme-vue.git" }, - "main": "index.js", - "types": "index.d.ts", + "main": "./cjs/index.js", + "module": "./esm/index.js", + "types": "./esm/index.d.ts", "scripts": { "clean": "gulp clean", "regenerate": "npm run clean && gulp generate", diff --git a/packages/devextreme-vue/src/core/version.ts b/packages/devextreme-vue/src/core/version.ts index 86d351198752..bc1ce25a128a 100644 --- a/packages/devextreme-vue/src/core/version.ts +++ b/packages/devextreme-vue/src/core/version.ts @@ -1,6 +1,6 @@ import * as VueType from 'vue'; -const Vue = (VueType as any).default || VueType; +const Vue = VueType[`${'default'}`] || VueType; export function getVueVersion() { const currentVersion = Vue.version; diff --git a/packages/devextreme-vue/tsconfig.esm.json b/packages/devextreme-vue/tsconfig.esm.json new file mode 100644 index 000000000000..e441ccc81afd --- /dev/null +++ b/packages/devextreme-vue/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "esnext", + "moduleResolution": "node", + "declaration": false, + }, +}