There's no automated verification that all material components are safe to use in node, i.e. pre-rendering with Angular Universal. See #306.
Create a step in the CI process to pre-compile a single root component which contains an instance of each material component. Use one of the Angular Universal pre-render libraries to build: https://github.com/angular/universal/tree/master/modules
Note: I'm planning to submit a Broccoli plugin to that repo which would work well with Angular CLI.
I'm willing to help set this up.
To report one problem unsolved in #774 and #883, Material is not working with Universal for now because of many reference to window
in Material umd bundles.
As proposed by @orangesoup, adding var window = undefined;
in Material umd bundles do the trick for now, and then Universal and Material work very well together in my test app.
I looked at Material TypeScript source files, and found very few direct reference to window
(and it's not the same as in umd bundles). So I think it is just a problem with the umd packaging system (maybe configured to target browsers). It's beyond my skills, but I think it's just a bundling option to change, and Material would already work with Universal.
Well I've been too optimist, the var window = undefined;
is causing problems on client side, so I suppose it's not just a bundling problem.
But I'm quite surprise to see so many references to window
, as we're supposed to avoid native dom and browser things inside Angular 2.
I confirm that window
references causing problems with Universal are just in umd bundles, which all starts by this kind of code :
var __extends = (window && window.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (window && window.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (window && window.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
I suppose this is polyfills, which are incorrectly checking on window
, supposing a browser environment.
I don't know how the bundling is done so I can't help, but I think it's not a big deal to correct that. It's really blocking to not be able to use Universal with Material just because of this.
@gdi2290 Problem is server-side, so I don't use webpack, I directly launch the TypeScript code with ts-node.
if you use ts-node directly then you have to wait for an update or just include a fake window object for now
var window = global
global.window = window
I have the universal-starter updated to fix the material package during build
https://github.com/angular/universal-starter
@gdi2290 Thanks, global patching is working as a workaround for now.
Now I have another issue I already met before, and I have no idea where it comes from :
Error: This method is not implemented in Parse5DomAdapter: Parse5DomAdapter#getCookie
at _notImplemented (/app/node_modules/angular2-platform-node/parse5-adapter.js:22:12)
at Parse5DomAdapter.getCookie (/app/node_modules/angular2-platform-node/parse5-adapter.js:625:15)
@gdi2290 But I'm not sure this is Universal or Material related, because with no Material, my app works just fine with Universal.
Issue created in Universal repo.
For the global patch workaround, just a note for other people interested, you need to do that :
var window = global;
global['window'] = window;
Doing global.window
directly causes an error.
@gdi2290 @cyrilletuzi How did you manage to get material work though? I'm getting an error like this:
.../node_modules/@angular2-material/core/ripple/ripple.js:10
import { NgModule, Directive, ElementRef, HostBinding, Input } from '@angular/core';
^^^^^^
SyntaxError: Unexpected token import
It seems like there's no umd for rippe (or anything under core
).
@orangesoup -- I removed ripple
from my application...
@JanStureNielsen Yeah well, that's an option as well. No other option yet I guess? Also... does that mean that I have to manually disable it for every single button/whatever that uses it?
@gdi2290
Any solution to lack of methods, when refering global
in window
variable, or we need for finalizing work on this issue?
EXCEPTION: window.requestAnimationFrame is not a function
ORIGINAL STACKTRACE:
TypeError: window.requestAnimationFrame is not a function
at /path/to/my/app/dist/server/index.js:10238:20
at ZoneDelegate.invoke (/path/to/my/app/node_modules/zone.js/dist/zone-node.js:203:28)
at Zone.run (/path/to/my/app/node_modules/zone.js/dist/zone-node.js:96:43)
at NgZoneImpl.runOuter (/path/to/my/app/node_modules/@angular/core/bundles/core.umd.js:6273:75)
at NgZone.runOutsideAngular (/path/to/my/app/node_modules/@angular/core/bundles/core.umd.js:6517:84)
at MdTabGroup.ngAfterViewChecked (/path/to/my/app/dist/server/index.js:10237:20)
at AppView._View_ProductsSettingsComponent0.detectChangesInternal (ProductsSettingsComponent.ngfactory.js:145:46)
at AppView.detectChanges (/path/to/my/app/node_modules/@angular/core/bundles/core.umd.js:9566:18)
at AppView.detectViewChildrenChanges (/path/to/my/app/node_modules/@angular/core/bundles/core.umd.js:9592:23)
at AppView.detectChangesInternal (/path/to/my/app/node_modules/@angular/core/bundles/core.umd.js:9577:18)
[TypeError: window.requestAnimationFrame is not a function]
@maciejsobala I had the same error as you. Try using https://github.com/chrisdickinson/raf
require('raf/polyfill');
in your server.ts
Material is broken again with Universal since alpha 9 (was working (with the window patch) with alpha 8).
Same (unhelpful) error as pre-alpha-8 :
.filter(function (task) { return task.data.eventName === eventName; })
TypeError: Cannot read property 'filter' of undefined
@gdi2290 mentions that RippleRenderer
needs to use Renderer
. This means https://github.com/angular/material2/blob/master/src/lib/core/ripple/ripple-renderer.ts#L50 and https://github.com/angular/material2/blob/master/src/lib/core/ripple/ripple-renderer.ts#L113 need to use renderer.createElement
instead of document.createElement
??
See here: https://github.com/angular/universal-starter/issues/185#issuecomment-250864200
any eta on this patch?
Found issues with the following code in md-input
:
this._elementType = elementRef.nativeElement.nodeName.toLowerCase() === 'md-input' ?
'input' :
'textarea';
@jelbourn should I create a pull request fixing this issue or you have someone already focusing on these issues? thanks
@krigton the important thing here is adding a job to the CI that runs over everything with Universal, otherwise it will keep breaking.
As for the input specifically, #1858 is changing the input quite a bit so that particular problem will likely soon be obsolete.
I see. it looked a good place to raise this problem. thanks.
@jelbourn Any update on Universal Support intentions, like being able to selectively load Material Modules as in @angular2-material. Because right now the only way to use Material with Universal safely is to load separate modules for server and front end.
@antonyRoberts I've found that the only thing causing issues (at least for me) is buttons. Everything else I've used works perfectly fine.
@antonyRoberts You can still selectively load individual component modules from @angular/material
.
@jelbourn while I'm doing this myself, should this be mentioned in the getting started docs? Happy to submit a pr for that, if it'd be of interest.
@yusijs Sure
@jelbourn
Is there anything I can help with this whole Universal++Material process?
Maybe we could talk sometime so I could get a better picture of what some of the roadblocks are.
Let me know!
Angular Universal is currently transitioning to live inside angular/angular
and will be undergoing some refactoring as it becomes part of core. The folks who are working on this recommended that we (Material) should wait until they're further along in that before we spend much time on making the component Universal-compatible.
That said, I'm okay with accepting small changes to the components that make it work today- I just don't want to significantly change any components until Universal's move is more complete.
Yeah know we're moving it to Core, but you might be right, maybe it's best to wait before making any bigger changes! It might all be easier once it's in Core as well :)
Any chance https://github.com/angular/material2/issues/2171 can be looked at as a 'small' change?
I'd hate to lock into an old version of material but this is currently breaking our project.
@timvdalen if you submit a PR that makes the platform detection happen lazily without changing the API that would be fine with me
It may be a good thing to wait for Universal to be merged in core, but some errors that are not supposed to happen in any Angular module (Universal-compatible or not) should be fixed now, as Material is now in beta. One example :
ReferenceError: document is not defined at RippleRenderer.createBackgroundIfNeeded
Many usages of browser-specific references (like window
, document
...) have been reported the last months, and most of them are still there (but the issues have all been closed).
Hello, please there's a workaround or I have to remove material2? :(
@fdambrosio Can you at least temporarily shut off server-side rendering from Universal so you can keep developing your app w/ Material for the time being?
yes @MarkPieszak we're developing without use Universal, our project works in AOT mode, but in ten days we have to go in production mode...
Most components are working with universal - buttons are fucky tho, so I've used mdl for those.
thanks @yusijs I've removed all md-button, but I have this error:
var hasV8BreakIterator = (window.Intl && window.Intl.v8BreakIterator);
^
ReferenceError: window is not defined
Seems like this is fixed: https://github.com/angular/material2/commit/e43677525dd83355c4115367121b296d39ec271d
thanks @yusijs
Just happy to help @fdambrosio :-)
now I can build with yarn run universal
but when I load a page I have this error:
EXCEPTION: navigator is not defined
ORIGINAL STACKTRACE:
ReferenceError: navigator is not defined
at new Platform (/app/node_modules/@angular/material/bundles/material.umd.js:26
03:36)
at eInjector.get (e.ngfactory.js:207:63)
at eInjector.get (e.ngfactory.js:232:122)
at eInjector.getInternal (e.ngfactory.js:664:60)
This is my current work around. It's a very big hack, but it does the work for me:
webpack.conf.ts
module: {
rules: [
{
test: /@angular(\\|\/)material/, use: "imports-loader?window=>global,CSS=>null,navigator=>{get userAgent(){return Zone.current.get('req')['headers']['user-agent'];}}"
}
]
}
__workaround.node.ts (at the end)
// Fix Universal Style
import { NodeDomRootRenderer, NodeDomRenderer } from 'angular2-universal/node';
function renderComponentFix(componentProto: any) {
return new NodeDomRenderer(this, componentProto, this._animationDriver);
}
NodeDomRootRenderer.prototype.renderComponent = renderComponentFix;
// End Fix Universal Style
// Material style fix
var createElementOriginal = NodeDomRenderer.prototype.createElement;
function createElementFix(parent: any, name: any, _debugInfo: any) {
var el = createElementOriginal.apply( this, [parent, name, _debugInfo] );
if ( el != null ) {
el.style = {};
el.nodeName = el.name;
}
return el;
}
NodeDomRenderer.prototype.createElement = createElementFix;
// Material style fix
// Material disable MdRipple work around.
import { MdRipple } from '@angular/material/core/ripple/ripple';
// Make these functions NOOP.
MdRipple.prototype.ngOnInit = function () {}
MdRipple.prototype.ngOnDestroy = function () {}
MdRipple.prototype.ngOnChanges = function ( changes: any ) {}
// Material disable MdRipple work around.
// Material disable ripple on Button work around.
import { MdButton } from '@angular/material/button/button';
MdButton.prototype._isRippleDisabled = function () {
return true;
};
// Material disable MdRipple work around.
// Disable observe content on the server.
import { ObserveContent } from '@angular/material/core/observe-content/observe-content';
ObserveContent.prototype.ngAfterContentInit = function () {}
// Disable observe content on the server.
That's so dirty. I like it. 👍👏
@gdi2290 Perfect. The webpack suggestion works well. I have updated my solution (hack!).
@mkhurramali @gdi2290 so what would the full work around look like?
He updated it above @jmurphzyo
@gdi2290 I'm using @angular/material
version 2.0.0-beta.2
and the webpack hack suggested by @mkhurramali. I had to add document=>global
to it too. Now I'm getting the following error:
TypeError: Invalid event target
at Function.module.exports.FromEventObservable.setupSubscription (/prerender-dist/index.js:150861:19)
at FromEventObservable.module.exports.FromEventObservable._subscribe (/prerender-dist/index.js:150883:29)
at FromEventObservable.module.exports.Observable.subscribe (/prerender-dist/index.js:629:27)
at new ScrollDispatcher (/prerender-dist/index.js:22124:106)
at SCROLL_DISPATCHER_PROVIDER_FACTORY (prerender-dist/index.js:22195:32)
I believe it is related to https://github.com/angular/material2/blob/b60d33fa441447580cfbcc61ddaf2b0c89080209/src/lib/core/overlay/scroll/scrollable.ts#L31
This is just one occurrence. There are other similar errors. I don't understand why. That snippet of code is using elementRef.nativeElement
. Which I thought was acceptable to use with Universal.
Thank you
My solution was tested with 2.0.0-beta.1
.
You can import individual modules:
import { MdButtonModule } from '@angular/material/button';
And then in your @NgModule
imports:
imports: [
MdButtonModule.forRoot()
]
@mkhurramali hi What about thé mdinput how fixing thé calling of document dom élément on thé constructor of mdinput on thé last version of thé matérial 2
@jeffbcross @jelbourn I would be really happy to help in this issue.
I have created a simple app with some Material components which is working with node: https://github.com/feloy/ng-univ
It is based on https://github.com/robwormald/ng-universal-demo
Feel free to explore the different commits to see some tricks necessary to make it work.
The app stops working when I try to use components using the Scrollable object, with the error noted by @winkerVSbecks above (Invalid event target).
Could I be of any help with putting in place this CI job to test the different components?
@feloy In addition to what @mkhurramali suggested I had to do this:
Downgrade to 2.0.0-beta.1
Scrollable object issue appeared in beta.2. I tried patching it but, it is a private method so I was not able to override it.
Some more additions to the hotfix:
// Used by mdInput
global['document'] = {
createElement() {
return {
setAttribute: function(type) { this.type = type; },
type: '',
classList: { add: noop },
};
},
};
// OverlayContainer
import { OverlayContainer } from '@angular/material/core';
OverlayContainer.prototype.getContainerElement = function() {
return { appendChild: noop } as any;
}
my version of the imports-loader:
{
test: /@angular(\\|\/)material/,
loader: 'imports-loader',
options: {
window: '>global',
'CSS': '>null',
navigator: '>{get userAgent(){ return \'Chrome\'; }}',
document: '>global.document',
},
},
I ended up using opaque tokens to provide DOM apis and mocked versions for the server. And use IS_BROWSER
/IS_SERVER
in a few places.
@NgModule({
...
providers: [
...
{ provide: IS_BROWSER, useValue: false },
{ provide: IS_SERVER, useValue: true },
{ provide: LOCAL_STORAGE, useClass: FakeStorage },
{ provide: SESSION_STORAGE, useClass: FakeStorage },
{ provide: NAVIGATOR, useClass: FakeNavigator },
{ provide: LiveAnnouncer, useClass: FakeLiveAnnouncer },
],
bootstrap: [AppComponent],
})
export class ServerModule { }
I suppose you could use the same strategy as LiveAnnouncer
to override Scrollable
object.
Currently my app is using these material modules: button, dialog, snack-bar, sidenav, progress-bar, input, checkbox, button-toggle, tooltip, select, radio, toolbar & core. And I am able to successfully pre-render.
As an aside… to get pre-render to work I had to create a new webpack build where this was the entry. This was because I am using webpack and I couldn't get the the pre-render plugin to use loaders during the prerender process. The code below is mostly adapted from the actual prerender plugin itself.
import 'ts-helpers';
import 'angular2-universal-polyfills';
import './universal-hotfix';
import './material-hotfix';
import { platformUniversalDynamic } from 'angular2-universal/node';
import { PrebootOptions } from 'preboot';
import * as fs from 'fs';
import * as path from 'path';
import { ServerModule } from '../src/server.module';
declare var Zone: any;
export interface UniversalPrerender {
...
}
const document = fs.readFileSync(
path.join(__dirname, '../dist/index.html'),
).toString();
const options: UniversalPrerender = {
ngModule: ServerModule,
time: false,
originUrl: 'http://localhost:8080',
baseUrl: 'http://localhost:8080',
requestUrl: 'http://localhost:8080',
preboot: {
eventSelectors: [...],
},
documentPath: './index.html',
document,
};
const platformRef: any = platformUniversalDynamic();
const zone = Zone.current.fork({
name: 'UNIVERSAL PRERENDER EXECUTION',
properties: options,
});
zone.run(() => (platformRef.serializeModule(
options.ngModule,
options,
))
.then((html) => {
if (typeof html !== 'string') {
console.error('Invalid HTML generated', html);
}
fs.writeFile(
path.join(__dirname, '../dist/search.html'),
html,
(err) => {
if (err) { console.error(err); }
/* tslint:disable:no-console */
console.info(`
✨ Generated the pre-rendered page successfully!✨
`);
/* tslint:enable:no-console */
});
}).catch(err => console.error(err)));
Here is an example that demos this approach: https://github.com/winkerVSbecks/ng2-prerenderer-example/tree/material (the material branch)
Has anyone managed to get @mkhurramali's workaround working with Material 2.0.0-beta.2 in a project based on @MarkPieszak's aspnetcore-angular2-universal?
I've tried putting the webpack.conf.ts workaround code suggested above into webpack.conf.js (after replacing input-loader with raw-loader), but getting "Call to Node module failed with error: Prerendering failed because of error: Error: Module parse failed: ...Angular2SpaClientappplatform-modulesapp.server.module.ts Unexpected character '@' (20:0).
Also, none of the sections of code in the __workaround.node.ts above seem to help if placed at the bottom of my __2.1.1.workaround.ts file, I get new related errors.
Any pearls of wisdom would be gratefully appreciated.
Hey all. I hate to shamelessly self-promote but @angular/material
works with my SSR library regardless of the references to document
and window
, and without any hacky monkey-patching or hotfixes. The project is located at https://github.com/clbond/angular-ssr. There are examples of how to use it at https://github.com/clbond/angular-ssr/tree/master/examples (both examples use @angular/material
to some extent). angular-ssr
also works with jQuery plugins and a variety of other things that break in both Angular Universal and @angular/platform-server
, because neither of them provide true DOM implementations.
@angular/material
will work with universal around versions 4.1.x in the meantime there are a few workarounds including frameworks, as @clbond suggested, that will add material support.
@clbond I like what you did with angular-ssr and a lot of what you have is what I was planning on having built into universal before the scope was lowered.
any updates on this? It appears angular 4.0.0 is published as of yesterday 3/23
@gpazo the msg above you says it's coming in 4.1 (ish) :)
We met recently to review places where Angular Material has to touch the DOM. We found that these all fell within three categories:
md-slider
needs to measure the width of the entire slider to that the track (the value part) can be set to the correct width. The approach for this will be to have a special JS snippet that will be delivered with the prerendered bundle to apply the correct styles.requestAnimationFrame
to animate (because IE11). The approach here will vary by component.The folks working on Angular Universal are going to be addressing these things in the near future.
This is great news. At the moment though this looks like the majority of the components. For example the MdButton component I guess falls into the first category? Does that mean nothing will be changed there in material, but something might be done in universal side to cope with that?
Most of cases in the first category will just end up inside of an "if (isPlatformBrowser)" check.
is there any work around of using getComputedStyle() in universal
Thanks
I have the same error.
Patrick(@gdi2290) is there a set of issues in @angular core that we can watch for the way you're solving this there. Would help with some other projects I'm working on on as well as what the material team is doing.
Hi @mariohmol you can get a working repo here: https://github.com/feloy/ng-univ
Note that it is working with material2-beta.1, not recent versions.
Hi there! Thanks for answering.. could not make work using ng-univ .. some libraries problems..
I could make this work porting my project to this example (https://github.com/clbond/angular-ssr/tree/master/examples/demand-express) .. with translate, server with mongoose and frontend with material.. so far so good =)
FYI: https://github.com/angular/material2/pull/4251 should be landing soon-ish
Does this mean material2 now works with the latest angular2-universal, or is there still work in progress?
@peterdobson i could make it working using https://github.com/clbond/angular-ssr
Thanks for the great efforts put into material2 - angular4+universal compatibility !
If I'm not wrong it reduced the "hacks" needed to 2 on my project:
module: {
rules: [
{
test: /@angular(\\|\/)material/,
loader: 'imports-loader',
options: {
window: '>global',
'CSS': '>null',
navigator: '>{get userAgent(){ return \'Chrome\'; }}',
document: '>global.document'
}
}
]
}
import { ObserveContent } from '@angular/material';
ObserveContent.prototype.ngAfterContentInit = function () {}
However I still run into Cannot set property 'transform' of undefined
when using MdTabs
due to getComputedStyle()
the element's style..
Any idea bout a workaround ?
For those with the same problem, I solved it this way for now:
// Noop to prevent calling applyCssTransform which try to apply transform on element.style
MdTabHeader.prototype._updateTabScrollPosition = function() {
To avoid getting this error
Invalid event target
at Function.FromEventObservable.setupSubscription (/app/webapp/dist/server.js:186614:19)
I also had to add
MdTabHeader.prototype.ngAfterContentInit = function() { }
Take in account that these noop prevent the prerender of inkbar and the style for the active tab
I can verify the problem is fixed now with #4635
Material2 is now working for me with Universal until the page is refreshed. I'm no expert on the subject, but these hacks currently seem to fix the server-side hangs/errors on page refresh.
Errors such as:
Microsoft.AspNetCore.NodeServices:Error: ERROR ReferenceError: document is not defined
at FocusTrap._createAnchor (mypathClientdistmain-server.js:25012:48)
Microsoft.AspNetCore.NodeServices:Error: ERROR ReferenceError: document is not defined
at FocusTrap._createAnchor (mypathClientdistmain-server.js:24962:48)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:Error: An unhandled exception has occurred while executing the request
System.Exception: Call to Node module failed with error: Prerendering failed because of error: Error: The module at mypath/Client/dist/main-server does not export a default function, and you have not specified which export to invoke.
at findRenderToStringFunc (myuserpathAppDataLocalTemptmpBBCD.tmp:140:20)
Microsoft.AspNetCore.NodeServices:Error: ERROR { Error: Uncaught (in promise): ReferenceError: requestAnimationFrame is not defined
ReferenceError: requestAnimationFrame is not defined
Microsoft.AspNetCore.NodeServices:Error: ERROR ReferenceError: MutationObserver is not defined
at MdMutationObserverFactory.create (mypathClientdistmain-server.js:21052:20)
Microsoft.AspNetCore.NodeServices:Error: ERROR { Error: Uncaught (in promise): TypeError: Cannot set property 'transform' of undefined
TypeError: Cannot set property 'transform' of undefined
at applyCssTransform (mypathClientdistmain-server.js:25958:29)
Hacks:
FYI: when encountering any errors with universal, reporting the errors here would be useful
@jelbourn Noted and updated in the comment above
Surfaced an issue w/ platform-browser when trying to test checkbox and toggle-button:
https://github.com/angular/angular/issues/17050
@azerafati As far as I understand your comment, you got angular material works with universal? How did you achieve that? I tried set dependencie to:
"@angular/material": "git+https://github.com/angular/material2-builds.git",
And I still get errors (ReferenceError: document is not defined
)
On current master most components should work with @angular/platform-server
. You can most specific errors here if you find otherwise.
You're right. I run into issue, because I had added BrowserAnimationsModule
(according to https://github.com/angular/material2/blob/master/guides/getting-started.md.
As I understand this module is common for some material components, so I should include it for example in my browser.module.ts. Am I right?
@maciejtreder did you figure it out? I have the same issue with BRowserAnimationModule
@maciejtreder @mchambaud You can fix the BrowserAnimationsModule using the fix listed over here
https://github.com/angular/angular/issues/15098#issuecomment-308863439
My Angular Universal Build runs just fine when I'm not using any components but everything is installed properly. However when I try to add an <md-toolbar>
I get the following error.
/Users/eddiehinkle/Development/personal/abode-angular/dist/ngfactory/node_modules/@angular/material/typings/index.ngfactory.ts:9
import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Unexpected token import
at createScript (vm.js:53:10)
at Object.runInThisContext (vm.js:95:10)
at Module._compile (module.js:543:28)
at Module._extensions..js (module.js:580:10)
at Object.require.extensions.(anonymous function) [as .ts] (/Users/eddiehinkle/Development/personal/abode-angular/node_modules/ts-node/src/index.ts:376:14)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
I'm running Angular Core 4.2.3 and Angular Material 2.0.0-beta7
Same issue than @EdwardHinkle
See https://github.com/TypeStrong/ts-node/issues/155
The problem is that ts-node will not compile anything in node_modules
, insisting that it should already be compiled to a node-compatible output. Also unfortunately, node doesn't support the ES6 import syntax (with good reason), which is why you see the error "Unexpected token import"
.
For our own CI, we work around this by building inside of the dist/
folder of our project (i.e., nothing is importing from node_modules
).
Need to investigate if there's anything we can do to work around this.
@jelbourn I don't quite understand what you're talking about. I checked node_modules/@angular/material
and it seems like I have the angular material build there (javascript files) not the source typescript files
Those JS output files use ES6 modules, though, which node does not support. You would need some tool to further process those imports.
the project is written in TS. Doesn't it mean that it can be compiled down to commonjs?
Ohh, so instead of importing a build, I probably need to import the source code and compile the TypeScript to commonjs to be used in Universal?
@EdwardHinkle same problem here, did you find a solution?
@CramericaIndustries nope, I've decided to give up on Angular Material 2 until they can properly support Universal. It's all a mess.
@EdwardHinkle thanks for your answer. I came to the same conclusion yesterday. Too bad that I've already spent some time on Material 2. What are you using instead?
@CramericaIndustries @EdwardHinkle
I am using https://github.com/qdouble/angular-webpack2-starter in production with Material 2 and Universal. Once the CLI fully supports Universal I will switch to that, but this is best template I've seen so far.
Here is my project: https://github.com/chrisvfabio/enw-angular
I have removed a lot of the clutter in the starter project, so feel free to use it as a template.
I'm also using https://github.com/devlint/gridlex for layouts as @angular/flex-layout doesn't support universal yet.
@chrisvfabio i havent tested the angular-webpack2-starter
, but testing your link enw-angular
, i can see that navigation between routes is not downloading the html rendered.. is just the first time... i dont know if that is optional or if is the natural behavior..
what i can tell is that the angular-ssr
project is fully working for me.. material2 and SSR without any problems until now
@mariohmol So the initial request to the server (i.e /home
) will go through the server.ts which uses the ngExpressEngine
engine to bootstrap the server module of the app to generate the rendered html and sends it back to the client.
view-source:https://essentialnordicwalking.com.au/home shows the initial paint.
The client then re-renders and bootstraps the client version of the app, then switches the server views with the client view and applies preboot.
After that, when routerLink
is triggered it behaves like a client-side app. My code isn't using lazy loaded modules, so all the routes are already bundled in the main-browser.js app.
angular-ssr
uses pre-rendering. The last time I used it, I had some problems with it building so I switched to angular-webpack2-starter
I have found another issues regarding of the server-side rendering of the following elements :
For MdSelect component the issue is located on the _getTriggerRect
method which basically calls browser nativeElementgetBoundingClientRect
method.
On MdTextareaAutosize, when the ngAfterViewInit
hook is called, some calculation based on the nativeElement are done.
These 2 first issues make the server-side rendered page crash.
And finally the issue about MdGridList is an issue regarding the RatioTyleStyler class and more specifically on the setRowStyles
and getComputedHeight
methods.
These methods define some styles to be applied on the tile, but the properties to be written are camelCase. On the browser this works well, but the server renderer writes theses properties inside the style attribute as they are.
Ex : style="marginTop: calc(((33.333333333333336% - ( 0px * 0.6666666666666666 )) + 0px) * 0);paddingTop:calc(((33.333333333333336% - ( 0px * 0.6666666666666666 )) * 1) + (0 * 0px));"
marginTop
and paddingTop
are not valid property names for the browser, therefore it ignore them.
I also experienced issues with the MdSelect.focus() and MdOption.focus() method, but it may be an issue from my side, I have to dig a little bit more to find out the issue.
Thx guys !
@jimjim2a would you be willing to file a standalone issue for each of those? Looks like they are real issues
@jelbourn sure, will do today !
Finally : got a real app, with material (beta.8) working with Universal ! Only problem is hammerjs
:
/node_modules/hammerjs/hammer.js:2643
})(window, document, 'Hammer');
^
ReferenceError: window is not defined
at Object.<anonymous> (/node_modules/hammerjs/hammer.js:2643:4)
Future solution : with dynamic imports from TS 2.4, I may be able to load hammerjs
only in browser context. But for now Angular is not compatible with TS 2.4.
@cyrilletuzi How did you make it work?
The issue can be pretty easily fixed in hammerjs
. Not the prettiest code, but works.
In the end of the file (or hammer.suffix.js
in src
):
replace })(window, document, 'Hammer');
with:
})(typeof window === 'undefined' ? null : window, typeof document === 'undefined' ? null : document, 'Hammer');
And in the prefix (hammer.prefix.js
in src
) add this after 'use strict';
if (!window || !document) return;
Well I didn't have any issue with Material itself, but I'm not using all the Material components, I'm using : Card, Button, Input, Toolbar, List, SnackBar, Slider, ProgressSpiner, Icons. The only issue is with hammer.
I may write a blog post about all the process.
@cyrilletuzi Yes, writing a blog post on your process would be great! If you do, please post the URL here so those of us having issues can read it :)
Nothing special about Material except hammerjs and FlexLayoutModule.
Very simple and obvious workaround for hammerjs
(don't know why I didn't think about it before) : you just have to import it in main.ts
(and _not_ in AppModule
or elsewhere), as this file will only be used for the browser bundle (the server bundle has a different entry point).
Did a PR to adapt the Getting started guide considering this.
@cyrilletuzi You are a genius. It was so simple and yet hard to find !
Thanks man !
Hello all,
Should MdSelect at this point work in universal? I am getting several issues with it but none with the other components.
ERROR { Error: Uncaught (in promise): TypeError: this._getHostElement(...).focus is not a function
and also
{ TypeError: this.trigger.nativeElement.getBoundingClientRect is not a function
@maciejtreder you are right, just faced the same problem and then moved BrowserAnimationsModule
to browser-app.module.ts
without specifying anything in server-app.module.ts
👍
@cyrilletuzi such a brillant idea to add hammer.js
to main.browser.ts
btw. just gonna let that here, if someone is facing following error:
return window && document && document.all && !window.atob;
ReferenceError: window is not defined
it's probably, because like me, your are importing the css theme with style-loader
in an import
. in such case, the provided trick about hammer.js
also applies, just move you import to main.browser.ts
respectively
import 'style-loader!../node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
Importing MdTabsModule
in one of my lazy
modules result in the following error on the server side:
ERROR ReferenceError: requestAnimationFrame is not defined
at /Users/me/Documents/project/dist/server.js:56104:13
at ZoneDelegate.invoke (/Users/me/Documents/project/dist/server.js:115885:26)
at Zone.run (/Users/me/Documents/project/dist/server.js:115635:43)
at NgZone.runOutsideAngular (/Users/me/Documents/project/dist/server.js:4798:83)
at MdInkBar.alignToElement (/Users/me/Documents/project/dist/server.js:56103:22)
at MdTabHeader._alignInkBarToSelectedTab (/Users/me/Documents/project/dist/server.js:56919:22)
at SafeSubscriber._next (/Users/me/Documents/project/dist/server.js:56658:23)
at SafeSubscriber.__tryOrSetError (/Users/me/Documents/project/dist/server.js:607:16)
at SafeSubscriber.next (/Users/me/Documents/project/dist/server.js:547:27)
at Subscriber._next (/Users/me/Documents/project/dist/server.js:485:26)
Any one may have a tips how to solve that? Or is it a bug?
requestAnimationFrame
is a browser function, so you get this error when the server try to pre-render.
To solve this importe a polyfill in you server.main.ts.
You can use this one for example https://github.com/ngryman/raf.js/
@julienR2 coolio thx, you are right that was the problem
I solved the problem like @johnnysainz suggested in following post https://github.com/angular/material2/issues/308
Respectively:
Install raf
npm install --save raf
In main.server.ts
added
require('raf/polyfill');
Is it possible to polyfill document, so Current document does not have a doctype. This may cause some Angular Material components not to behave as expected.
will not occur on server side?
hi, when we'll have a full support of Universal+Material on Angular?
The basic test for Angular Material support has been added. Please open individual issues for anything else you might encounter with using Angular material on the server.
Hello, same problem with angular material universal
/Users/liuqinghua/workspace/example/activity-front/dist/ngfactory/node_modules/@angular/material/typings/index.ngfactory.ts:9
import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Unexpected token import
The bug has existed for a long time ! No one has a good solution for it?
@BlankHrt see this comment for a solution that works around the issue.
Same problem than @BlankHrt , hammerjs seems to have nothing to do with this error. I didn't import it anywhere, but I have the exact same error :
/dist/ngfactory/node_modules/@angular/material/typings/index.ngfactory.ts:9
import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Unexpected token import
Any idea?
Hi ! I would need some info to help you out.
Hope we can figure out what's going on !
@glemiere I am having the exact same issue here:
import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Unexpected token import
I didn't import HammerJs anywhere.
Hey guys!
For some reasons this repos works with material design, SSR and AOT. You can see it in action right here.
I think the problem is coming from a misconfiguration of the server side rendering in my (our) setup(s), because I've been able to fix this issue by double checking the official instructions.
I'm going to use this repo for my own needs, just to earn some time, it's a pretty good seed. Thanks to @JayChase for his answer on my stackoverflow post
Hey guys.
I need to render matDialog on the server side. I see that it's impossible for now because @angular/material uses the document object for the dialogs rendering.
Could you please tell me will you add possibility to render dialogs on the backend?
If yes please tell me do you have an idea when this changes will be released?
We don't have plans to support overlay-based components rendering on the server at this time (dialogs, menus, etc.). For the vast majority of cases, these components are only rendered in response to user interaction
Ok. Got it. Thanks
Отправлено с iPhone
25 окт. 2017 г., в 19:52, Jeremy Elbourn notifications@github.com написал(а):
We don't have plans to support overlay-based components rendering on the server at this time (dialogs, menus, etc.). For the vast majority of cases, these components are only rendered in response to user interaction
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
How about the error
Users/hoangcuulong/website-cli-beecow/dist/server.js:218913
__extends(LoginFormModel, _super);
^
ReferenceError: __extends is not defined
at /Users/hoangcuulong/website-cli-beecow/dist/server.js:218913:5
at Object.../../../../../src/app/_models/login.model.ts (/Users/hoangcuulong/website-cli-beecow/dist/server.js:218920:2)
at __webpack_require__ (/Users/hoangcuulong/website-cli-beecow/dist/server.js:164408:30)
at Object.../../../../../src/app/_models/index.ts (/Users/hoangcuulong/website-cli-beecow/dist/server.js:218497:10)
at __webpack_require__ (/Users/hoangcuulong/website-cli-beecow/dist/server.js:164408:30)
at Object.../../../../../src/app/_shared/utils/beecow.utils.ts (/Users/hoangcuulong/website-cli-beecow/dist/server.js:224130:15)
at __webpack_require__ (/Users/hoangcuulong/website-cli-beecow/dist/server.js:164408:30)
at Object.../../../../../src/app/market/popup-location/popup-location.component.ts (/Users/hoangcuulong/website-cli-beecow/dist/server.js:229039:22)
at __webpack_require__ (/Users/hoangcuulong/website-cli-beecow/dist/server.js:164408:30)
at Object.../../../../../src/$$_gendir/app/market/popup-location/popup-location.component.ngfactory.ts (/Users/hoangcuulong/website-cli-beecow/dist/server.js:177242:10)
While I extends two Model?
@jelbourn In reference to MatDialog, MatMenu, and render-only-on-interaction components, how are we supposed to properly handle this?
I couldn't quickly find any documentation on SSR with angular material, I checked here: https://material.angular.io/guides as well as on the component itself, https://material.angular.io/components/menu/overview
Additionally, in the given example, https://material.angular.io/components/menu/examples mat-menu
fails on universal.
If you could give some guidance on what we're supposed to do, I'd happily write the guide and submit a PR.
I agree with @damienwebdev
there's no docs about SSR and Material
Closing this now since everything should mostly work with SRR this this point in time. Individual bugs can be tracked via standalone issues.
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
Very simple and obvious workaround for
hammerjs
(don't know why I didn't think about it before) : you just have to import it inmain.ts
(and _not_ inAppModule
or elsewhere), as this file will only be used for the browser bundle (the server bundle has a different entry point).Did a PR to adapt the Getting started guide considering this.