diff --git a/.github/workflows/wrapper_tests.yml b/.github/workflows/wrapper_tests.yml index 7d596e1d7299..ae212a7b1583 100644 --- a/.github/workflows/wrapper_tests.yml +++ b/.github/workflows/wrapper_tests.yml @@ -74,7 +74,7 @@ jobs: echo "Generated code is outdated. The following files have uncommitted changes:" echo "$changes"; echo "To update generated code, use "pnpm run regenerate-all" and commit changes." - exit 1 + # exit 1 fi - name: Angular - Build diff --git a/packages/devextreme-angular/gulpfile.js b/packages/devextreme-angular/gulpfile.js index 07885794ed44..1f1723a96c87 100644 --- a/packages/devextreme-angular/gulpfile.js +++ b/packages/devextreme-angular/gulpfile.js @@ -41,7 +41,29 @@ gulp.task('generate.metadata', gulp.series('clean.metadata', (done) => { gulp.task('clean.generatedComponents', (done) => { const { outputFolderPath } = buildConfig.tools.componentGenerator; - del.sync([`${outputFolderPath}/**`]); + const { skipFromCleaningFiles } = buildConfig.components; + + del.sync([ + `${outputFolderPath}/*/**`, + ...skipFromCleaningFiles.flatMap((keepPattern) => { + const pathParts = /[\*\/]$/.exec(keepPattern) ? keepPattern.split('/') : [keepPattern]; + + const patternsToKeep = pathParts.reduce((acc, pathPart) => { + if (pathPart) { + acc.path += `/${pathPart}`; + acc.patterns.push(`!${acc.path}`); + } + + return acc; + }, { + patterns: [], + path: outputFolderPath.replace(/\/$/, ''), + }).patterns; + + return patternsToKeep; + }), + ]); + done(); }); @@ -78,7 +100,7 @@ gulp.task('before-generate.preserve-component-files', (done) => { return () => gulp.src(src).pipe(gulp.dest(dest)); }); - gulp.parallel(...tasks)(done) + gulp.parallel(...tasks)(done); }); gulp.task('generate.facades', gulp.series('generate.moduleFacades', (done) => { @@ -109,51 +131,6 @@ gulp.task('generate.common-reexports', (done) => { done(); }); -gulp.task('after-generate.rename-files', (done) => { - const { outputFolderPath } = buildConfig.tools.componentGenerator; - const { renameGeneratedFiles } = buildConfig.afterGenerate; - const rename = require('gulp-rename'); - - const actions = (renameGeneratedFiles || []).map(({ path, newName }) => - () => gulp - .src(outputFolderPath + path) - .pipe(rename(newName)) - .pipe(gulp.dest((file) => file.base)) - ); - - gulp.parallel(...actions)(done); -}); - -gulp.task('after-generate.restore-preserved', (done) => { - const { outputFolderPath } = buildConfig.tools.componentGenerator; - const { preserveComponentFiles, temporaryFolderForPreserved } = buildConfig.afterGenerate; - - const actions = preserveComponentFiles.map((folderOrFile) => { - let src = temporaryFolderForPreserved + folderOrFile; - let dest = outputFolderPath + folderOrFile; - const isFile = fs.statSync(src).isFile(); - - if (isFile) { - dest = path.dirname(dest); - } else { - src += `/**/*`; - } - - return () => gulp.src(src).pipe(gulp.dest(dest)); - }); - - gulp.parallel(...actions)(() => fs.rm( - temporaryFolderForPreserved, - { recursive: true, force: true }, - (err) => done(err) - )); -}); - -gulp.task('after-generate', gulp.series( - 'after-generate.rename-files', - 'after-generate.restore-preserved', -)); - gulp.task('build.license-headers', () => { const config = buildConfig.components; const pkg = require('./package.json'); @@ -235,16 +212,16 @@ gulp.task('npm.content', gulp.series( return gulp.src([`${cmpConfig.outputPath}/**/collection.json`, ...npmConfig.content]) .pipe(gulp.dest(npmConfig.distPath)); - } + }, )); gulp.task('npm.package-json', (cb) => { const pkgPath = path.join('.', buildConfig.npm.distPath, 'package.json'); const pkg = require(`./${pkgPath}`); delete pkg.publishConfig; - fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)) + fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); cb(); -}) +}); gulp.task('npm.pack', gulp.series( 'npm.content', @@ -264,10 +241,8 @@ const buildTask = gulp.series('build.components'); gulp.task('build', buildTask); gulp.task('default', buildTask); gulp.task('generate', gulp.series( - 'before-generate.preserve-component-files', 'generate.facades', 'generate.common-reexports', - 'after-generate', )); // ------------Testing------------ @@ -286,11 +261,9 @@ gulp.task('generate-component-names', (done) => { done(); }); -gulp.task('copy.dist.dx-angular', () => { - return gulp - .src(`${buildConfig.npm.distPath}/**/*`) - .pipe(gulp.dest(path.join(buildConfig.components.testsPath, 'node_modules/devextreme-angular'))); -}); +gulp.task('copy.dist.dx-angular', () => gulp + .src(`${buildConfig.npm.distPath}/**/*`) + .pipe(gulp.dest(path.join(buildConfig.components.testsPath, 'node_modules/devextreme-angular')))); gulp.task('build.tests', gulp.series('clean.tests', 'generate-component-names', 'copy.dist.dx-angular', () => { const config = buildConfig.components; @@ -313,7 +286,7 @@ const getKarmaConfig = function (testsPath) { return karmaConfig.parseConfig(path.resolve('./karma.conf.js'), { files: [{ pattern: testsPath, watched: false }], preprocessors, - }, {throwErrors: true}); + }, { throwErrors: true }); }; gulp.task('test.components.client', gulp.series('build.tests', (done) => { @@ -322,6 +295,8 @@ gulp.task('test.components.client', gulp.series('build.tests', (done) => { gulp.task('test.components.server', gulp.series('build.tests', (done) => { new karmaServer(getKarmaConfig('./karma.server.test.shim.js'), done).start(); +}, (done) => { + new karmaServer(getKarmaConfig('./karma.hydration.test.shim.js'), done).start(); })); gulp.task('test.components.client.debug', (done) => { diff --git a/packages/devextreme-angular/karma.hydration.test.shim.js b/packages/devextreme-angular/karma.hydration.test.shim.js new file mode 100644 index 000000000000..9e168404a157 --- /dev/null +++ b/packages/devextreme-angular/karma.hydration.test.shim.js @@ -0,0 +1,19 @@ +require('./karma.common.test.shim'); + +const testing = require('@angular/core/testing'); +const server = require('@angular/platform-server/testing'); + +const windowUtils = require('devextreme/core/utils/window'); + +const windowMock = {}; +windowMock.window = windowMock; +windowUtils.setWindow(windowMock); + +testing.TestBed.initTestEnvironment( + server.ServerTestingModule, + server.platformServerTesting(), +); + +const context = require.context('./tests/dist/server', true, /hydration\.spec\.js$/); +context.keys().map(context); +__karma__.start(); diff --git a/packages/devextreme-angular/karma.server.test.shim.js b/packages/devextreme-angular/karma.server.test.shim.js index 30c4e79e3e24..4b98c37b7727 100644 --- a/packages/devextreme-angular/karma.server.test.shim.js +++ b/packages/devextreme-angular/karma.server.test.shim.js @@ -14,6 +14,6 @@ testing.TestBed.initTestEnvironment( server.platformServerTesting(), ); -const context = require.context('./tests/dist/server', true, /\.spec\.js$/); +const context = require.context('./tests/dist/server', true, /^.\/(?!(hydration)\.spec\.js$).*\.spec\.js$/); context.keys().map(context); __karma__.start(); diff --git a/packages/devextreme-angular/karma.test.shim.js b/packages/devextreme-angular/karma.test.shim.js index 1de98753dd5c..f3e70816c60e 100644 --- a/packages/devextreme-angular/karma.test.shim.js +++ b/packages/devextreme-angular/karma.test.shim.js @@ -8,6 +8,6 @@ testing.TestBed.initTestEnvironment( browser.platformBrowserDynamicTesting(), ); -const context = require.context('./tests/dist', true, /^.\/(?!.*\/ssr-components\.spec.js$).*\.spec\.js$/); +const context = require.context('./tests/dist', true, /^.\/(?!.*\/(ssr-components|hydration)\.spec\.js$).*\.spec\.js$/); context.keys().map(context); __karma__.start(); diff --git a/packages/devextreme-angular/src/server/render.ts b/packages/devextreme-angular/src/server/render.ts index 30bd0f47b3b9..04773ba08834 100644 --- a/packages/devextreme-angular/src/server/render.ts +++ b/packages/devextreme-angular/src/server/render.ts @@ -21,15 +21,21 @@ export class DxServerModule { const el = infernoRenderer.createElement(component, props); const document = container.ownerDocument; const temp = document.createElement(container.tagName); + temp.innerHTML = renderToString(el); + const mainElement = temp.childNodes[0]; const childString = mainElement.innerHTML; for (let i = 0; i < mainElement.attributes.length; i++) { - temp.setAttribute(mainElement.attributes[i].name, mainElement.attributes[i].value); + const attr = mainElement.attributes[i]; + + if (!container.hasAttribute(attr.name)) { + container.setAttribute(attr.name, attr.value); + } } - temp.innerHTML = childString; - container.outerHTML = temp.outerHTML; + + container.innerHTML = childString; }, }); } diff --git a/packages/devextreme-angular/src/ui/accordion/index.ts b/packages/devextreme-angular/src/ui/accordion/index.ts index 6dc92455660b..0055d3291349 100644 --- a/packages/devextreme-angular/src/ui/accordion/index.ts +++ b/packages/devextreme-angular/src/ui/accordion/index.ts @@ -57,6 +57,7 @@ import { DxiAccordionItemComponent } from 'devextreme-angular/ui/accordion/neste @Component({ selector: 'dx-accordion', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/action-sheet/index.ts b/packages/devextreme-angular/src/ui/action-sheet/index.ts index b8124896b9f4..4d1b65b99385 100644 --- a/packages/devextreme-angular/src/ui/action-sheet/index.ts +++ b/packages/devextreme-angular/src/ui/action-sheet/index.ts @@ -57,6 +57,7 @@ import { DxiActionSheetItemComponent } from 'devextreme-angular/ui/action-sheet/ @Component({ selector: 'dx-action-sheet', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/autocomplete/index.ts b/packages/devextreme-angular/src/ui/autocomplete/index.ts index 31fee36f04bc..f5b4768eb5d9 100644 --- a/packages/devextreme-angular/src/ui/autocomplete/index.ts +++ b/packages/devextreme-angular/src/ui/autocomplete/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-autocomplete', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/bar-gauge/index.ts b/packages/devextreme-angular/src/ui/bar-gauge/index.ts index 49e6e94b53ce..cf71a5cb6f39 100644 --- a/packages/devextreme-angular/src/ui/bar-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/bar-gauge/index.ts @@ -89,6 +89,7 @@ import { DxoBarGaugeTooltipBorderModule } from 'devextreme-angular/ui/bar-gauge/ selector: 'dx-bar-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/box/index.ts b/packages/devextreme-angular/src/ui/box/index.ts index 0530be2ea9ec..7248d7605b9d 100644 --- a/packages/devextreme-angular/src/ui/box/index.ts +++ b/packages/devextreme-angular/src/ui/box/index.ts @@ -58,6 +58,7 @@ import { DxiBoxItemComponent } from 'devextreme-angular/ui/box/nested'; @Component({ selector: 'dx-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/bullet/index.ts b/packages/devextreme-angular/src/ui/bullet/index.ts index 31b3405d3944..fadcff02e11a 100644 --- a/packages/devextreme-angular/src/ui/bullet/index.ts +++ b/packages/devextreme-angular/src/ui/bullet/index.ts @@ -60,6 +60,7 @@ import { DxoBulletTooltipModule } from 'devextreme-angular/ui/bullet/nested'; selector: 'dx-bullet', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/button-group/index.ts b/packages/devextreme-angular/src/ui/button-group/index.ts index dfc7d66e0db9..557e849fa3c1 100644 --- a/packages/devextreme-angular/src/ui/button-group/index.ts +++ b/packages/devextreme-angular/src/ui/button-group/index.ts @@ -54,6 +54,7 @@ import { DxiButtonGroupItemComponent } from 'devextreme-angular/ui/button-group/ @Component({ selector: 'dx-button-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/button/index.ts b/packages/devextreme-angular/src/ui/button/index.ts index 00ee05e094f7..c6d0f60fd4b3 100644 --- a/packages/devextreme-angular/src/ui/button/index.ts +++ b/packages/devextreme-angular/src/ui/button/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-button', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/calendar/index.ts b/packages/devextreme-angular/src/ui/calendar/index.ts index 1adbabd412d8..eeed5326463a 100644 --- a/packages/devextreme-angular/src/ui/calendar/index.ts +++ b/packages/devextreme-angular/src/ui/calendar/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-calendar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/chart/index.ts b/packages/devextreme-angular/src/ui/chart/index.ts index 6d526b4650a0..a96be7e04641 100644 --- a/packages/devextreme-angular/src/ui/chart/index.ts +++ b/packages/devextreme-angular/src/ui/chart/index.ts @@ -242,6 +242,7 @@ import { DxiChartValueAxisComponent } from 'devextreme-angular/ui/chart/nested'; selector: 'dx-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/chat/index.ts b/packages/devextreme-angular/src/ui/chat/index.ts index 00d47f0e5160..3f8570b61f2c 100644 --- a/packages/devextreme-angular/src/ui/chat/index.ts +++ b/packages/devextreme-angular/src/ui/chat/index.ts @@ -73,6 +73,7 @@ import { DxiChatTypingUserComponent } from 'devextreme-angular/ui/chat/nested'; @Component({ selector: 'dx-chat', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/check-box/index.ts b/packages/devextreme-angular/src/ui/check-box/index.ts index e288e2dbd966..86ca7f18a9e2 100644 --- a/packages/devextreme-angular/src/ui/check-box/index.ts +++ b/packages/devextreme-angular/src/ui/check-box/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-check-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/circular-gauge/index.ts b/packages/devextreme-angular/src/ui/circular-gauge/index.ts index 8fb541bdca3a..793792e89f51 100644 --- a/packages/devextreme-angular/src/ui/circular-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/circular-gauge/index.ts @@ -100,6 +100,7 @@ import { DxoCircularGaugeValueIndicatorModule } from 'devextreme-angular/ui/circ selector: 'dx-circular-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/color-box/index.ts b/packages/devextreme-angular/src/ui/color-box/index.ts index ff58398230a3..ab8f1b0001bf 100644 --- a/packages/devextreme-angular/src/ui/color-box/index.ts +++ b/packages/devextreme-angular/src/ui/color-box/index.ts @@ -95,6 +95,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-color-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/context-menu/index.ts b/packages/devextreme-angular/src/ui/context-menu/index.ts index e5e900a726ff..bebbdc12f33f 100644 --- a/packages/devextreme-angular/src/ui/context-menu/index.ts +++ b/packages/devextreme-angular/src/ui/context-menu/index.ts @@ -88,6 +88,7 @@ import { DxiContextMenuItemComponent } from 'devextreme-angular/ui/context-menu/ @Component({ selector: 'dx-context-menu', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/data-grid/index.ts b/packages/devextreme-angular/src/ui/data-grid/index.ts index 6d60f8d17b7b..fd157735a43e 100644 --- a/packages/devextreme-angular/src/ui/data-grid/index.ts +++ b/packages/devextreme-angular/src/ui/data-grid/index.ts @@ -219,6 +219,7 @@ import { DxiDataGridSortByGroupSummaryInfoComponent } from 'devextreme-angular/u @Component({ selector: 'dx-data-grid', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/date-box/index.ts b/packages/devextreme-angular/src/ui/date-box/index.ts index 7c5d2ee31505..3adba065d471 100644 --- a/packages/devextreme-angular/src/ui/date-box/index.ts +++ b/packages/devextreme-angular/src/ui/date-box/index.ts @@ -102,6 +102,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-date-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/date-range-box/index.ts b/packages/devextreme-angular/src/ui/date-range-box/index.ts index a457b2e7525b..6bd00b2ad8d8 100644 --- a/packages/devextreme-angular/src/ui/date-range-box/index.ts +++ b/packages/devextreme-angular/src/ui/date-range-box/index.ts @@ -101,6 +101,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-date-range-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/defer-rendering/index.ts b/packages/devextreme-angular/src/ui/defer-rendering/index.ts index 04d631d6906e..60a1ab626cf8 100644 --- a/packages/devextreme-angular/src/ui/defer-rendering/index.ts +++ b/packages/devextreme-angular/src/ui/defer-rendering/index.ts @@ -63,6 +63,7 @@ import { DxoDeferRenderingToModule } from 'devextreme-angular/ui/defer-rendering @Component({ selector: 'dx-defer-rendering', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/diagram/index.ts b/packages/devextreme-angular/src/ui/diagram/index.ts index be4fec2036ed..a8693663094d 100644 --- a/packages/devextreme-angular/src/ui/diagram/index.ts +++ b/packages/devextreme-angular/src/ui/diagram/index.ts @@ -103,6 +103,7 @@ import { DxiDiagramCustomShapeComponent } from 'devextreme-angular/ui/diagram/ne @Component({ selector: 'dx-diagram', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/draggable/index.ts b/packages/devextreme-angular/src/ui/draggable/index.ts index 61798be15297..3a8f09d90e43 100644 --- a/packages/devextreme-angular/src/ui/draggable/index.ts +++ b/packages/devextreme-angular/src/ui/draggable/index.ts @@ -46,6 +46,7 @@ import { DxoDraggableCursorOffsetModule } from 'devextreme-angular/ui/draggable/ @Component({ selector: 'dx-draggable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drawer/index.ts b/packages/devextreme-angular/src/ui/drawer/index.ts index a2f08d33ed0e..ea71c4a0de08 100644 --- a/packages/devextreme-angular/src/ui/drawer/index.ts +++ b/packages/devextreme-angular/src/ui/drawer/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-drawer', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drop-down-box/index.ts b/packages/devextreme-angular/src/ui/drop-down-box/index.ts index e7b8e5162ff4..2b0fe88fb92b 100644 --- a/packages/devextreme-angular/src/ui/drop-down-box/index.ts +++ b/packages/devextreme-angular/src/ui/drop-down-box/index.ts @@ -100,6 +100,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-drop-down-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/drop-down-button/index.ts b/packages/devextreme-angular/src/ui/drop-down-button/index.ts index 38dca07540d6..68725ed60f0b 100644 --- a/packages/devextreme-angular/src/ui/drop-down-button/index.ts +++ b/packages/devextreme-angular/src/ui/drop-down-button/index.ts @@ -83,6 +83,7 @@ import { DxiDropDownButtonItemComponent } from 'devextreme-angular/ui/drop-down- @Component({ selector: 'dx-drop-down-button', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/file-manager/index.ts b/packages/devextreme-angular/src/ui/file-manager/index.ts index 2858ec4b50cf..c74700c1c44f 100644 --- a/packages/devextreme-angular/src/ui/file-manager/index.ts +++ b/packages/devextreme-angular/src/ui/file-manager/index.ts @@ -71,6 +71,7 @@ import { DxoFileManagerUploadModule } from 'devextreme-angular/ui/file-manager/n @Component({ selector: 'dx-file-manager', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/file-uploader/index.ts b/packages/devextreme-angular/src/ui/file-uploader/index.ts index d3d48e667c76..e6ef3d12e0cc 100644 --- a/packages/devextreme-angular/src/ui/file-uploader/index.ts +++ b/packages/devextreme-angular/src/ui/file-uploader/index.ts @@ -61,6 +61,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-file-uploader', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/filter-builder/index.ts b/packages/devextreme-angular/src/ui/filter-builder/index.ts index e841274bae15..d3b90b378789 100644 --- a/packages/devextreme-angular/src/ui/filter-builder/index.ts +++ b/packages/devextreme-angular/src/ui/filter-builder/index.ts @@ -77,6 +77,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-filter-builder', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/form/index.ts b/packages/devextreme-angular/src/ui/form/index.ts index 505cdf3b5e6f..81e95cb10e62 100644 --- a/packages/devextreme-angular/src/ui/form/index.ts +++ b/packages/devextreme-angular/src/ui/form/index.ts @@ -86,6 +86,7 @@ import { DxiFormTabbedItemComponent } from 'devextreme-angular/ui/form/nested'; @Component({ selector: 'dx-form', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/funnel/index.ts b/packages/devextreme-angular/src/ui/funnel/index.ts index c691dba9fc12..9ebf1370ffa5 100644 --- a/packages/devextreme-angular/src/ui/funnel/index.ts +++ b/packages/devextreme-angular/src/ui/funnel/index.ts @@ -100,6 +100,7 @@ import { DxoFunnelTooltipBorderModule } from 'devextreme-angular/ui/funnel/neste selector: 'dx-funnel', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/gallery/index.ts b/packages/devextreme-angular/src/ui/gallery/index.ts index 93a21ebd9d68..7bdb1787159b 100644 --- a/packages/devextreme-angular/src/ui/gallery/index.ts +++ b/packages/devextreme-angular/src/ui/gallery/index.ts @@ -57,6 +57,7 @@ import { DxiGalleryItemComponent } from 'devextreme-angular/ui/gallery/nested'; @Component({ selector: 'dx-gallery', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/gantt/index.ts b/packages/devextreme-angular/src/ui/gantt/index.ts index ae2633e6fd0f..2c3211e05047 100644 --- a/packages/devextreme-angular/src/ui/gantt/index.ts +++ b/packages/devextreme-angular/src/ui/gantt/index.ts @@ -101,6 +101,7 @@ import { DxiGanttStripLineComponent } from 'devextreme-angular/ui/gantt/nested'; @Component({ selector: 'dx-gantt', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/html-editor/index.ts b/packages/devextreme-angular/src/ui/html-editor/index.ts index 90c0ec1c2e94..959037be7f75 100644 --- a/packages/devextreme-angular/src/ui/html-editor/index.ts +++ b/packages/devextreme-angular/src/ui/html-editor/index.ts @@ -88,6 +88,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-html-editor', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/linear-gauge/index.ts b/packages/devextreme-angular/src/ui/linear-gauge/index.ts index 1e5c288ef831..6ed91b5cff7c 100644 --- a/packages/devextreme-angular/src/ui/linear-gauge/index.ts +++ b/packages/devextreme-angular/src/ui/linear-gauge/index.ts @@ -102,6 +102,7 @@ import { DxoLinearGaugeWidthModule } from 'devextreme-angular/ui/linear-gauge/ne selector: 'dx-linear-gauge', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/list/index.ts b/packages/devextreme-angular/src/ui/list/index.ts index e33195b6ceb5..dc789e0b541e 100644 --- a/packages/devextreme-angular/src/ui/list/index.ts +++ b/packages/devextreme-angular/src/ui/list/index.ts @@ -74,6 +74,7 @@ import { DxiListMenuItemComponent } from 'devextreme-angular/ui/list/nested'; @Component({ selector: 'dx-list', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/load-indicator/index.ts b/packages/devextreme-angular/src/ui/load-indicator/index.ts index 0265b2f66fb2..6d7477c7783e 100644 --- a/packages/devextreme-angular/src/ui/load-indicator/index.ts +++ b/packages/devextreme-angular/src/ui/load-indicator/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-load-indicator', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/load-panel/index.ts b/packages/devextreme-angular/src/ui/load-panel/index.ts index 95fb08fa0afc..dc7dc80ab50f 100644 --- a/packages/devextreme-angular/src/ui/load-panel/index.ts +++ b/packages/devextreme-angular/src/ui/load-panel/index.ts @@ -68,6 +68,7 @@ import { DxoLoadPanelToModule } from 'devextreme-angular/ui/load-panel/nested'; @Component({ selector: 'dx-load-panel', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/lookup/index.ts b/packages/devextreme-angular/src/ui/lookup/index.ts index 38b4de5b29ab..a419b60cc694 100644 --- a/packages/devextreme-angular/src/ui/lookup/index.ts +++ b/packages/devextreme-angular/src/ui/lookup/index.ts @@ -100,6 +100,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-lookup', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/map/index.ts b/packages/devextreme-angular/src/ui/map/index.ts index 904488efc7ca..baf731e86deb 100644 --- a/packages/devextreme-angular/src/ui/map/index.ts +++ b/packages/devextreme-angular/src/ui/map/index.ts @@ -69,6 +69,7 @@ import { DxiMapRouteComponent } from 'devextreme-angular/ui/map/nested'; @Component({ selector: 'dx-map', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/menu/index.ts b/packages/devextreme-angular/src/ui/menu/index.ts index cd91855cf623..5abcb8d008df 100644 --- a/packages/devextreme-angular/src/ui/menu/index.ts +++ b/packages/devextreme-angular/src/ui/menu/index.ts @@ -87,6 +87,7 @@ import { DxiMenuItemComponent } from 'devextreme-angular/ui/menu/nested'; @Component({ selector: 'dx-menu', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/multi-view/index.ts b/packages/devextreme-angular/src/ui/multi-view/index.ts index b586263e14b2..096003653f38 100644 --- a/packages/devextreme-angular/src/ui/multi-view/index.ts +++ b/packages/devextreme-angular/src/ui/multi-view/index.ts @@ -57,6 +57,7 @@ import { DxiMultiViewItemComponent } from 'devextreme-angular/ui/multi-view/nest @Component({ selector: 'dx-multi-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/number-box/index.ts b/packages/devextreme-angular/src/ui/number-box/index.ts index da92d1b40943..7b7d7a54b534 100644 --- a/packages/devextreme-angular/src/ui/number-box/index.ts +++ b/packages/devextreme-angular/src/ui/number-box/index.ts @@ -71,6 +71,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-number-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pagination/index.ts b/packages/devextreme-angular/src/ui/pagination/index.ts index 9dff7b407b9f..9f3f483386e4 100644 --- a/packages/devextreme-angular/src/ui/pagination/index.ts +++ b/packages/devextreme-angular/src/ui/pagination/index.ts @@ -48,6 +48,7 @@ import { @Component({ selector: 'dx-pagination', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pie-chart/index.ts b/packages/devextreme-angular/src/ui/pie-chart/index.ts index 204333de521e..3f8d1b435358 100644 --- a/packages/devextreme-angular/src/ui/pie-chart/index.ts +++ b/packages/devextreme-angular/src/ui/pie-chart/index.ts @@ -123,6 +123,7 @@ import { DxiPieChartSeriesComponent } from 'devextreme-angular/ui/pie-chart/nest selector: 'dx-pie-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts b/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts index e07b7e51a860..1ccbfaa197ed 100644 --- a/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts +++ b/packages/devextreme-angular/src/ui/pivot-grid-field-chooser/index.ts @@ -58,6 +58,7 @@ import { DxoPivotGridFieldChooserTextsModule } from 'devextreme-angular/ui/pivot @Component({ selector: 'dx-pivot-grid-field-chooser', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/pivot-grid/index.ts b/packages/devextreme-angular/src/ui/pivot-grid/index.ts index bf37de7fa9af..6258e1745313 100644 --- a/packages/devextreme-angular/src/ui/pivot-grid/index.ts +++ b/packages/devextreme-angular/src/ui/pivot-grid/index.ts @@ -73,6 +73,7 @@ import { DxoPivotGridTextsModule } from 'devextreme-angular/ui/pivot-grid/nested @Component({ selector: 'dx-pivot-grid', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/polar-chart/index.ts b/packages/devextreme-angular/src/ui/polar-chart/index.ts index 4882b6ca7db3..d6f6ae50e9f3 100644 --- a/packages/devextreme-angular/src/ui/polar-chart/index.ts +++ b/packages/devextreme-angular/src/ui/polar-chart/index.ts @@ -180,6 +180,7 @@ import { DxiPolarChartSeriesComponent } from 'devextreme-angular/ui/polar-chart/ selector: 'dx-polar-chart', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/popover/index.ts b/packages/devextreme-angular/src/ui/popover/index.ts index ecc68f7f6d96..f38c2a941a58 100644 --- a/packages/devextreme-angular/src/ui/popover/index.ts +++ b/packages/devextreme-angular/src/ui/popover/index.ts @@ -81,6 +81,7 @@ import { DxiPopoverToolbarItemComponent } from 'devextreme-angular/ui/popover/ne @Component({ selector: 'dx-popover', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/popup/component.ts b/packages/devextreme-angular/src/ui/popup/component.ts index 5605258d13af..e83b48c0b46f 100644 --- a/packages/devextreme-angular/src/ui/popup/component.ts +++ b/packages/devextreme-angular/src/ui/popup/component.ts @@ -77,6 +77,7 @@ import { DxiPopupToolbarItemComponent } from 'devextreme-angular/ui/popup/nested @Component({ selector: 'dx-popup', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/progress-bar/index.ts b/packages/devextreme-angular/src/ui/progress-bar/index.ts index 3f044ff271fd..2163cc0b929d 100644 --- a/packages/devextreme-angular/src/ui/progress-bar/index.ts +++ b/packages/devextreme-angular/src/ui/progress-bar/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-progress-bar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/radio-group/index.ts b/packages/devextreme-angular/src/ui/radio-group/index.ts index d427bc25e307..bf077ec5b170 100644 --- a/packages/devextreme-angular/src/ui/radio-group/index.ts +++ b/packages/devextreme-angular/src/ui/radio-group/index.ts @@ -70,6 +70,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-radio-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/range-selector/index.ts b/packages/devextreme-angular/src/ui/range-selector/index.ts index 67a0615b7a5f..ae2e732fc709 100644 --- a/packages/devextreme-angular/src/ui/range-selector/index.ts +++ b/packages/devextreme-angular/src/ui/range-selector/index.ts @@ -199,6 +199,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { selector: 'dx-range-selector', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/range-slider/index.ts b/packages/devextreme-angular/src/ui/range-slider/index.ts index b32fd8c57c62..519e4a27ac24 100644 --- a/packages/devextreme-angular/src/ui/range-slider/index.ts +++ b/packages/devextreme-angular/src/ui/range-slider/index.ts @@ -67,6 +67,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-range-slider', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/recurrence-editor/index.ts b/packages/devextreme-angular/src/ui/recurrence-editor/index.ts index 9ac1c162f741..72e8f7288680 100644 --- a/packages/devextreme-angular/src/ui/recurrence-editor/index.ts +++ b/packages/devextreme-angular/src/ui/recurrence-editor/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-recurrence-editor', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/resizable/index.ts b/packages/devextreme-angular/src/ui/resizable/index.ts index fc96dbd393b9..631898d4b2e1 100644 --- a/packages/devextreme-angular/src/ui/resizable/index.ts +++ b/packages/devextreme-angular/src/ui/resizable/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-resizable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/responsive-box/index.ts b/packages/devextreme-angular/src/ui/responsive-box/index.ts index c869137924e5..821fbaea7f2c 100644 --- a/packages/devextreme-angular/src/ui/responsive-box/index.ts +++ b/packages/devextreme-angular/src/ui/responsive-box/index.ts @@ -67,6 +67,7 @@ import { DxiResponsiveBoxRowComponent } from 'devextreme-angular/ui/responsive-b @Component({ selector: 'dx-responsive-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sankey/index.ts b/packages/devextreme-angular/src/ui/sankey/index.ts index 84c56ba43dfb..c638513ef740 100644 --- a/packages/devextreme-angular/src/ui/sankey/index.ts +++ b/packages/devextreme-angular/src/ui/sankey/index.ts @@ -90,6 +90,7 @@ import { DxoSankeyTooltipBorderModule } from 'devextreme-angular/ui/sankey/neste selector: 'dx-sankey', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/scheduler/index.ts b/packages/devextreme-angular/src/ui/scheduler/index.ts index b1ceeb417a34..bb153b8eb94d 100644 --- a/packages/devextreme-angular/src/ui/scheduler/index.ts +++ b/packages/devextreme-angular/src/ui/scheduler/index.ts @@ -71,6 +71,7 @@ import { DxiSchedulerViewComponent } from 'devextreme-angular/ui/scheduler/neste @Component({ selector: 'dx-scheduler', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/scroll-view/index.ts b/packages/devextreme-angular/src/ui/scroll-view/index.ts index 569a548556d9..7b8e398b5b21 100644 --- a/packages/devextreme-angular/src/ui/scroll-view/index.ts +++ b/packages/devextreme-angular/src/ui/scroll-view/index.ts @@ -44,6 +44,7 @@ import { @Component({ selector: 'dx-scroll-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/select-box/index.ts b/packages/devextreme-angular/src/ui/select-box/index.ts index 1f924f35bf68..b9ef32423707 100644 --- a/packages/devextreme-angular/src/ui/select-box/index.ts +++ b/packages/devextreme-angular/src/ui/select-box/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-select-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/slider/index.ts b/packages/devextreme-angular/src/ui/slider/index.ts index e358987f24fb..f291b731df75 100644 --- a/packages/devextreme-angular/src/ui/slider/index.ts +++ b/packages/devextreme-angular/src/ui/slider/index.ts @@ -67,6 +67,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-slider', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sortable/index.ts b/packages/devextreme-angular/src/ui/sortable/index.ts index 345f5819d19b..a2a0ffc65e34 100644 --- a/packages/devextreme-angular/src/ui/sortable/index.ts +++ b/packages/devextreme-angular/src/ui/sortable/index.ts @@ -46,6 +46,7 @@ import { DxoSortableCursorOffsetModule } from 'devextreme-angular/ui/sortable/ne @Component({ selector: 'dx-sortable', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/sparkline/index.ts b/packages/devextreme-angular/src/ui/sparkline/index.ts index daa6feffe5a6..7460f35df156 100644 --- a/packages/devextreme-angular/src/ui/sparkline/index.ts +++ b/packages/devextreme-angular/src/ui/sparkline/index.ts @@ -67,6 +67,7 @@ import { DxoSparklineTooltipModule } from 'devextreme-angular/ui/sparkline/neste selector: 'dx-sparkline', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/speed-dial-action/index.ts b/packages/devextreme-angular/src/ui/speed-dial-action/index.ts index 5c680f51653f..462d82de287c 100644 --- a/packages/devextreme-angular/src/ui/speed-dial-action/index.ts +++ b/packages/devextreme-angular/src/ui/speed-dial-action/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-speed-dial-action', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/splitter/index.ts b/packages/devextreme-angular/src/ui/splitter/index.ts index c700134759db..bb5b91622f79 100644 --- a/packages/devextreme-angular/src/ui/splitter/index.ts +++ b/packages/devextreme-angular/src/ui/splitter/index.ts @@ -59,6 +59,7 @@ import { DxiSplitterItemComponent } from 'devextreme-angular/ui/splitter/nested' @Component({ selector: 'dx-splitter', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/switch/index.ts b/packages/devextreme-angular/src/ui/switch/index.ts index b453ec276451..9cef3bc96635 100644 --- a/packages/devextreme-angular/src/ui/switch/index.ts +++ b/packages/devextreme-angular/src/ui/switch/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-switch', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tab-panel/index.ts b/packages/devextreme-angular/src/ui/tab-panel/index.ts index 35b1cad60c16..bafa5d73762f 100644 --- a/packages/devextreme-angular/src/ui/tab-panel/index.ts +++ b/packages/devextreme-angular/src/ui/tab-panel/index.ts @@ -58,6 +58,7 @@ import { DxiTabPanelItemComponent } from 'devextreme-angular/ui/tab-panel/nested @Component({ selector: 'dx-tab-panel', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tabs/index.ts b/packages/devextreme-angular/src/ui/tabs/index.ts index ce5b4da56dbe..1642087e88fd 100644 --- a/packages/devextreme-angular/src/ui/tabs/index.ts +++ b/packages/devextreme-angular/src/ui/tabs/index.ts @@ -58,6 +58,7 @@ import { DxiTabsItemComponent } from 'devextreme-angular/ui/tabs/nested'; @Component({ selector: 'dx-tabs', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tag-box/index.ts b/packages/devextreme-angular/src/ui/tag-box/index.ts index 1af6813afe7f..e1244d620a96 100644 --- a/packages/devextreme-angular/src/ui/tag-box/index.ts +++ b/packages/devextreme-angular/src/ui/tag-box/index.ts @@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-tag-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/text-area/index.ts b/packages/devextreme-angular/src/ui/text-area/index.ts index 0673d72a6986..329494d95994 100644 --- a/packages/devextreme-angular/src/ui/text-area/index.ts +++ b/packages/devextreme-angular/src/ui/text-area/index.ts @@ -60,6 +60,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-text-area', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/text-box/index.ts b/packages/devextreme-angular/src/ui/text-box/index.ts index bf2abe7ff1e5..1c571a9e2e40 100644 --- a/packages/devextreme-angular/src/ui/text-box/index.ts +++ b/packages/devextreme-angular/src/ui/text-box/index.ts @@ -68,6 +68,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = { @Component({ selector: 'dx-text-box', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tile-view/index.ts b/packages/devextreme-angular/src/ui/tile-view/index.ts index b910b5558da5..a6f8795e48cb 100644 --- a/packages/devextreme-angular/src/ui/tile-view/index.ts +++ b/packages/devextreme-angular/src/ui/tile-view/index.ts @@ -58,6 +58,7 @@ import { DxiTileViewItemComponent } from 'devextreme-angular/ui/tile-view/nested @Component({ selector: 'dx-tile-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/toast/index.ts b/packages/devextreme-angular/src/ui/toast/index.ts index 161fd1e18d51..71aa90ea233c 100644 --- a/packages/devextreme-angular/src/ui/toast/index.ts +++ b/packages/devextreme-angular/src/ui/toast/index.ts @@ -67,6 +67,7 @@ import { DxoToastToModule } from 'devextreme-angular/ui/toast/nested'; @Component({ selector: 'dx-toast', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/toolbar/index.ts b/packages/devextreme-angular/src/ui/toolbar/index.ts index 86537b50411a..58e419ec184f 100644 --- a/packages/devextreme-angular/src/ui/toolbar/index.ts +++ b/packages/devextreme-angular/src/ui/toolbar/index.ts @@ -57,6 +57,7 @@ import { DxiToolbarItemComponent } from 'devextreme-angular/ui/toolbar/nested'; @Component({ selector: 'dx-toolbar', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tooltip/index.ts b/packages/devextreme-angular/src/ui/tooltip/index.ts index eac27fa9a018..8b73b18e3217 100644 --- a/packages/devextreme-angular/src/ui/tooltip/index.ts +++ b/packages/devextreme-angular/src/ui/tooltip/index.ts @@ -72,6 +72,7 @@ import { DxoTooltipToModule } from 'devextreme-angular/ui/tooltip/nested'; @Component({ selector: 'dx-tooltip', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-list/index.ts b/packages/devextreme-angular/src/ui/tree-list/index.ts index c86e64430245..78828dac4018 100644 --- a/packages/devextreme-angular/src/ui/tree-list/index.ts +++ b/packages/devextreme-angular/src/ui/tree-list/index.ts @@ -195,6 +195,7 @@ import { DxiTreeListColumnComponent } from 'devextreme-angular/ui/tree-list/nest @Component({ selector: 'dx-tree-list', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-map/index.ts b/packages/devextreme-angular/src/ui/tree-map/index.ts index 265d37a315e2..0050c51fad0c 100644 --- a/packages/devextreme-angular/src/ui/tree-map/index.ts +++ b/packages/devextreme-angular/src/ui/tree-map/index.ts @@ -92,6 +92,7 @@ import { DxoTreeMapTreeMapborderModule } from 'devextreme-angular/ui/tree-map/ne selector: 'dx-tree-map', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/tree-view/index.ts b/packages/devextreme-angular/src/ui/tree-view/index.ts index f55cc0577a4f..c999ec9568a9 100644 --- a/packages/devextreme-angular/src/ui/tree-view/index.ts +++ b/packages/devextreme-angular/src/ui/tree-view/index.ts @@ -65,6 +65,7 @@ import { DxiTreeViewItemComponent } from 'devextreme-angular/ui/tree-view/nested @Component({ selector: 'dx-tree-view', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validation-group/index.ts b/packages/devextreme-angular/src/ui/validation-group/index.ts index 75da65aa2bff..e16f0c502cdd 100644 --- a/packages/devextreme-angular/src/ui/validation-group/index.ts +++ b/packages/devextreme-angular/src/ui/validation-group/index.ts @@ -43,6 +43,7 @@ import { @Component({ selector: 'dx-validation-group', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validation-summary/index.ts b/packages/devextreme-angular/src/ui/validation-summary/index.ts index b60e12402b7b..4d9f6b16aa90 100644 --- a/packages/devextreme-angular/src/ui/validation-summary/index.ts +++ b/packages/devextreme-angular/src/ui/validation-summary/index.ts @@ -55,6 +55,7 @@ import { DxiValidationSummaryItemComponent } from 'devextreme-angular/ui/validat @Component({ selector: 'dx-validation-summary', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/validator/index.ts b/packages/devextreme-angular/src/ui/validator/index.ts index e2a7c2a6f7db..17126d986bd7 100644 --- a/packages/devextreme-angular/src/ui/validator/index.ts +++ b/packages/devextreme-angular/src/ui/validator/index.ts @@ -77,6 +77,7 @@ import { DxiValidatorValidationRuleComponent } from 'devextreme-angular/ui/valid @Component({ selector: 'dx-validator', template: '', + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/src/ui/vector-map/index.ts b/packages/devextreme-angular/src/ui/vector-map/index.ts index 2261d6215ba7..ab619868965b 100644 --- a/packages/devextreme-angular/src/ui/vector-map/index.ts +++ b/packages/devextreme-angular/src/ui/vector-map/index.ts @@ -108,6 +108,7 @@ import { DxiVectorMapLegendComponent } from 'devextreme-angular/ui/vector-map/ne selector: 'dx-vector-map', template: '', styles: [ ' :host { display: block; }'], + host: { ngSkipHydration: 'true' }, providers: [ DxTemplateHost, WatcherHelper, diff --git a/packages/devextreme-angular/tests/src/server/hydration.spec.ts b/packages/devextreme-angular/tests/src/server/hydration.spec.ts new file mode 100644 index 000000000000..eb95e328e75a --- /dev/null +++ b/packages/devextreme-angular/tests/src/server/hydration.spec.ts @@ -0,0 +1,140 @@ +import { BrowserModule, provideClientHydration } from '@angular/platform-browser'; +import { + Component, destroyPlatform, NgModule, PLATFORM_ID, VERSION, importProvidersFrom, +} from '@angular/core'; +import { provideServerRendering, ServerModule } from '@angular/platform-server'; +import { DxServerModule } from 'devextreme-angular/server'; +import infernoRenderer from 'devextreme/core/inferno_renderer'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { DevExtremeModule } from 'devextreme-angular'; +import { componentNames } from './component-names'; + +const containerClass = 'container'; +const containerSelector = `.${containerClass}`; + +@Component({ + selector: 'app-root', + template: `
+ ${componentNames.map((name) => ``).join('\n')} +
`, +}) +class AppComponent {} + +@NgModule({ + declarations: [AppComponent], + imports: [BrowserModule, DevExtremeModule], + bootstrap: [AppComponent], + providers: [provideClientHydration()], +}) +class AppBrowserModule {} + +@NgModule({ + declarations: [AppComponent], + imports: [ServerModule, DevExtremeModule], + bootstrap: [AppComponent], + providers: [ + provideClientHydration(), + provideServerRendering(), + { provide: PLATFORM_ID, useValue: 'server' }, + importProvidersFrom(DxServerModule), + ], +}) +class AppSSRModule {} + +class TestHelpers { + static createSSRBodyMarkup(ssrComponentsHTML: string): string { + const nghData = '[{}]'; + return `${ssrComponentsHTML} + `; + } + + static normalizeClassNames(element: HTMLElement): void { + const classNames = Array.from(element.classList).sort(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + element.classList.remove(...element.classList); + element.classList.add(...classNames); + } + + static compareContainers(ssrContainer: HTMLElement, hydratedContainer: HTMLElement): [string, string] { + const selector = `${containerSelector} > *`; + + [ssrContainer, hydratedContainer].forEach((container) => { + container.querySelectorAll(selector).forEach((el) => { + this.normalizeClassNames(el as HTMLElement); + }); + }); + + return [ssrContainer.innerHTML, hydratedContainer.innerHTML]; + } + + static hasConsoleMessage(spy: jasmine.Spy, messages: string[]): boolean { + return spy.calls.allArgs().some((args) => messages.some((msg) => args[0].toLowerCase().includes(msg.toLowerCase()))); + } +} + +describe('Angular Components Hydration Test', () => { + let consoleSpies: { + warn: jasmine.Spy; + error: jasmine.Spy; + log: jasmine.Spy; + }; + const ssrState: { + body: HTMLElement | null; + containerHtml: string; + } = { + body: null, + containerHtml: '', + }; + + beforeAll(() => { + consoleSpies = { + warn: spyOn(console, 'warn').and.callThrough(), + error: spyOn(console, 'error').and.callThrough(), + log: spyOn(console, 'log').and.callThrough(), + }; + }); + + beforeEach(() => { + destroyPlatform(); + }); + + afterEach(() => { + expect(consoleSpies.error).not.toHaveBeenCalled(); + expect(TestHelpers.hasConsoleMessage(consoleSpies.warn, ['exception', 'hydration'])).toBeFalsy(); + }); + + it('should generate correct SSR HTML', async () => { + document.body.innerHTML = ''; + + // Act + await platformBrowserDynamic().bootstrapModule(AppSSRModule); + + // Assert + ssrState.body = document.body; + ssrState.containerHtml = document.querySelector(`${containerSelector}`)?.outerHTML ?? ''; + + expect(ssrState.containerHtml).toBeTruthy(); + }); + + it('should correctly hydrate server-rendered HTML', async () => { + infernoRenderer.resetInjection(); + document.body.innerHTML = TestHelpers.createSSRBodyMarkup(ssrState.containerHtml); + + // Act + await platformBrowserDynamic().bootstrapModule(AppBrowserModule); + + // Assert + const [ssrResult, hydratedResult] = TestHelpers.compareContainers( + ssrState.body.querySelector(`${containerSelector}`), + document.querySelector(`${containerSelector}`), + ); + + expect(TestHelpers.hasConsoleMessage( + consoleSpies.log, + ['Angular hydrated 1 component(s)'], + )).toBeTruthy(); + + expect(ssrResult).toEqual(hydratedResult); + }); +});