Skip to content

Commit 965aade

Browse files
Fix double rendering of components in SSR mode after hydration in Angular (#28685)
1 parent 9c6c6e9 commit 965aade

File tree

89 files changed

+266
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+266
-20
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"axe-core": "4.10.2",
4545
"cheerio": "1.0.0-rc.10",
4646
"codelyzer": "6.0.2",
47-
"devextreme-internal-tools": "16.3.0",
47+
"devextreme-internal-tools": "16.3.1",
4848
"http-server": "14.1.1",
4949
"husky": "8.0.3",
5050
"jest": "29.7.0",

packages/devextreme-angular/gulpfile.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ gulp.task('before-generate.preserve-component-files', (done) => {
101101
return () => gulp.src(src).pipe(gulp.dest(dest));
102102
});
103103

104-
gulp.parallel(...tasks)(done)
104+
gulp.parallel(...tasks)(done);
105105
});
106106

107107
gulp.task('generate.facades', gulp.series('generate.moduleFacades', (done) => {
@@ -213,16 +213,16 @@ gulp.task('npm.content', gulp.series(
213213

214214
return gulp.src([`${cmpConfig.outputPath}/**/collection.json`, ...npmConfig.content])
215215
.pipe(gulp.dest(npmConfig.distPath));
216-
}
216+
},
217217
));
218218

219219
gulp.task('npm.package-json', (cb) => {
220220
const pkgPath = path.join('.', buildConfig.npm.distPath, 'package.json');
221221
const pkg = require(`./${pkgPath}`);
222222
delete pkg.publishConfig;
223-
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2))
223+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
224224
cb();
225-
})
225+
});
226226

227227
gulp.task('npm.pack', gulp.series(
228228
'npm.content',
@@ -298,6 +298,8 @@ gulp.task('test.components.client', gulp.series('build.tests', (done) => {
298298

299299
gulp.task('test.components.server', gulp.series('build.tests', (done) => {
300300
new karmaServer(getKarmaConfig('./karma.server.test.shim.js'), done).start();
301+
}, (done) => {
302+
new karmaServer(getKarmaConfig('./karma.hydration.test.shim.js'), done).start();
301303
}));
302304

303305
gulp.task('test.components.client.debug', (done) => {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
require('./karma.common.test.shim');
2+
3+
const testing = require('@angular/core/testing');
4+
const server = require('@angular/platform-server/testing');
5+
6+
const windowUtils = require('devextreme/core/utils/window');
7+
8+
const windowMock = {};
9+
windowMock.window = windowMock;
10+
windowUtils.setWindow(windowMock);
11+
12+
testing.TestBed.initTestEnvironment(
13+
server.ServerTestingModule,
14+
server.platformServerTesting(),
15+
);
16+
17+
const context = require.context('./tests/dist/server', true, /hydration\.spec\.js$/);
18+
context.keys().map(context);
19+
__karma__.start();

packages/devextreme-angular/karma.server.test.shim.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ testing.TestBed.initTestEnvironment(
1414
server.platformServerTesting(),
1515
);
1616

17-
const context = require.context('./tests/dist/server', true, /\.spec\.js$/);
17+
const context = require.context('./tests/dist/server', true, /^.\/(?!(hydration)\.spec\.js$).*\.spec\.js$/);
1818
context.keys().map(context);
1919
__karma__.start();

packages/devextreme-angular/karma.test.shim.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ testing.TestBed.initTestEnvironment(
88
browser.platformBrowserDynamicTesting(),
99
);
1010

11-
const context = require.context('./tests/dist', true, /^.\/(?!.*\/ssr-components\.spec.js$).*\.spec\.js$/);
11+
const context = require.context('./tests/dist', true, /^.\/(?!.*\/(ssr-components|hydration)\.spec\.js$).*\.spec\.js$/);
1212
context.keys().map(context);
1313
__karma__.start();

packages/devextreme-angular/src/server/render.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,21 @@ export class DxServerModule {
2121
const el = infernoRenderer.createElement(component, props);
2222
const document = container.ownerDocument;
2323
const temp = document.createElement(container.tagName);
24+
2425
temp.innerHTML = renderToString(el);
26+
2527
const mainElement = temp.childNodes[0];
2628
const childString = mainElement.innerHTML;
2729

2830
for (let i = 0; i < mainElement.attributes.length; i++) {
29-
temp.setAttribute(mainElement.attributes[i].name, mainElement.attributes[i].value);
31+
const attr = mainElement.attributes[i];
32+
33+
if (!container.hasAttribute(attr.name)) {
34+
container.setAttribute(attr.name, attr.value);
35+
}
3036
}
31-
temp.innerHTML = childString;
32-
container.outerHTML = temp.outerHTML;
37+
38+
container.innerHTML = childString;
3339
},
3440
});
3541
}

packages/devextreme-angular/src/ui/accordion/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { DxiAccordionItemComponent } from 'devextreme-angular/ui/accordion/neste
5757
@Component({
5858
selector: 'dx-accordion',
5959
template: '',
60+
host: { ngSkipHydration: 'true' },
6061
providers: [
6162
DxTemplateHost,
6263
WatcherHelper,

packages/devextreme-angular/src/ui/action-sheet/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { DxiActionSheetItemComponent } from 'devextreme-angular/ui/action-sheet/
5757
@Component({
5858
selector: 'dx-action-sheet',
5959
template: '',
60+
host: { ngSkipHydration: 'true' },
6061
providers: [
6162
DxTemplateHost,
6263
WatcherHelper,

packages/devextreme-angular/src/ui/autocomplete/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ const CUSTOM_VALUE_ACCESSOR_PROVIDER = {
103103
@Component({
104104
selector: 'dx-autocomplete',
105105
template: '',
106+
host: { ngSkipHydration: 'true' },
106107
providers: [
107108
DxTemplateHost,
108109
WatcherHelper,

packages/devextreme-angular/src/ui/bar-gauge/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ import { DxoBarGaugeTooltipBorderModule } from 'devextreme-angular/ui/bar-gauge/
8989
selector: 'dx-bar-gauge',
9090
template: '',
9191
styles: [ ' :host { display: block; }'],
92+
host: { ngSkipHydration: 'true' },
9293
providers: [
9394
DxTemplateHost,
9495
WatcherHelper,

0 commit comments

Comments
 (0)