angular / universal Goto Github PK
View Code? Open in Web Editor NEWServer-side rendering and Prerendering for Angular
License: MIT License
Server-side rendering and Prerendering for Angular
License: MIT License
We need e2e tests for
Server:
Server+Client:
Server+Client+Preboot.js
Hi,
I have some free time and decided to contribute ^^
However, when trying to npm install, I had some issues with git not able to clone the angular submodule (see screenshot below).
My git version is 2.3.5
But good news is I fixed this issue by adding git submodule init &&
at the beginning of the NPM angular-submodule
task.
I will submit the corresponding PR soon.
A service for server concerns such as but not limited to SEO.
related interface proposals angular/angular#3144 (comment)
Either Environment
that's bound by di to Server
or Client
. There is also an optimization step per environment that will be solved via Webpack build
prior art https://github.com/DerMambo/ms-seo
var robotTxt = `
User-agent: Twitterbot
Disallow:
User-agent: *
Disallow: /
`;
var metatags = `
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@nytimesbits" />
<meta name="twitter:creator" content="@nickbilton" />
<meta property="og:url" content="http://bits.blogs.nytimes.com/2011/12/08/a-twitter-for-my-sister/" />
<meta property="og:title" content="A Twitter for My Sister" />
<meta property="og:description" content="In the early days, Twitter grew so quickly that it was almost impossible to add new features because engineers spent their time trying to keep the rocket ship from stalling." />
<meta property="og:image" content="http://graphics8.nytimes.com/images/2011/12/08/technology/bits-newtwitter/bits-newtwitter-tmagArticle.jpg" />
`;
@Component()
@View()
@RouteConfig()
class App {
constructor(server: Server) {
server.set('title', 'My home page');
server.set('robot.txt', robotTxt);
server.set('metatags', metatags);
}
}
@Component({
selector: 'app',
bindings: [ bind(Environment).toClass(Server) ]
})
@View({
})
class App {
constructor(env: Environment) {
}
}
the idea here is replacing express with angular itself for a server framework. Where you have a Server App that has a view which is the Universal app
optional change(s) in angular (We could implement ourselves).
we currently don't allow the developer to buildCache, clearCache, remove Injector, rebuildBindings, or any sort of way to change the state of the Application Instance
extend ApplicationRef ourselves and maintain it as it's out of sync with the one created in Angular
Give the developer a lot more control over the lifecycle of our Application on the server. We're unable to predict any sort of optimizations developers would do with their system.
Allow the developer to have more control (for example)
import {bootstrap} from 'angular2/universal/server';
import {App} from 'universal/App';
import {server} from 'server/server';
var appRef = bootstrap(App, [serverServiceBindings]);
appRef.getClientRoutes().forEach(setNoJavaScriptRoutes(setServerRoutes(server)));
server.get('/', (req, res) => {
// prepare stateful app
var statefulApp = appRef.createStateful();
// async data would be solved by checking cache first as microtask
statefulApp.cache(req.jsonData);
var Service = statefulApp.injector.get(Service);
Service.cache(req.jsonData);
statefulApp.router.setState(req.url, req.params, req.body);
// trigger routes or actions
statefulApp.tick();
// serialize
var content = statefulApp.toString();
statefulApp.dispose();
res.send(content);
});
easier example
import {bootstrap, setNoJavaScriptRoutes, setServerRoutes} from 'angular2/universal/server';
import {App} from 'universal/App';
import {server} from 'server/express_server';
var appRef = bootstrap(App, [serverServiceBindings]);
setNoJavaScriptRoutes(setServerRoutes(appRef.getClientRoutes, server)));
server.get('/', (req, res) => {
var appJson = {url: req.url, params: req.params, data: req.jsonData};
res.send(appRef.createStateful(appJson).disposeToString());
});
There should be a simple solution for working with "complex" models when dealing with server rendered views
An Angular app on the Client that's in a WebWorker should also be able to start off server rendered and preboot.js
I'm choosing only the most popular framework for each language for now
@gdi2290: Scala (Play Framework) gdi2290/play-angular2
I'm currently working on a Scala (Play Framework) example of rendering an Angular 2 app in my personal github then promote the example to the examples/
once proof of concept is met. At the moment I'm running the app in a NodeEnvironment.
Blocked due to a problem trying to load a bundled version of commonjs Angular 2
e2e tests are global and remain in root while module tests should remain within the module
change in angular
document
document
we create a document once then an element during each request to append it to the document and remove it afterwards.
There is no reason why we need the whole document
on the server on each request unless the use mutates the document
outside of the app (which is why we have been reusing one instance). At the moment we're creating the app element for each request and appending it to our document to render then removing it. This is due to createRootHostView
createRootHostView() {
var element = DOM.querySelector(this._document, hostElementSelector);
}
this is limiting since you need a host element with the app element and to overwrite ShadowDomStrategy with the correct styleHost.
bind(ShadowDomStrategy).toFactory(doc => {
return new EmulatedUnscopedShadowDomStrategy(doc.head);
}, [DOCUMENT_TOKEN]),
There needs to be a way for developers to preload their json data on the server to be sent to the client for to grab out of the preloaded cache.
<module import="/preloadCache.js"></module>
<script>window.preloadCache.setRef('request');</script>
<app></app>
<module import="/preboot.js"></module>
<module>
import {bootstrap} from '@angular/angular';
import {App} from './app';
bootstrap(App, []);
</module>
<script>window.preloadCache.complete('request', { data: 'serverData' });</script>
It's important that the PreloadCache can happen after bootstrap as the serialized data could be a large data set that is being streamed down to the client with the html
This is really easy to do since you could just include a Node version of XMLHttpRequest (called NodeXhr) that replaces BrowserXhr for an MVP
in this file modules/server/src/http_server.ts
replace XMLHttpRequest with a node version xmlhttprequest as NodeXhr
and reuse the same XHRBackend
with bind(ConnectionBackend) .toClass(XHRBackend)
rather than NodeBackend
and that should work
Using protractor
npm module. Should test:
To make the test more robust, we might want to defer the client bootstrap until we click a special extra button, so we are sure we can do asserts on the server rendered version and then on the version that was replaced by the client.
currently server rendering is broken after pulling latest
Working with gulp it would be great to use Webpack when building our TypeScript files to commonjs
it would be great to start generating a changelog via conventional-changelog
Examples should be isolated and shouldn't be in modules since it's not a module. This also requires the webpack build system to simplify configuration. We also need an index page that would link to each example and this would also help with protractor e2e
Consider different ways to construct e2e tests such as Page Object Pattern or Bot Pattern (conventions for protractor e2e)
currently uses browserify but we should switch to webpack
npm scripts can only go so far and we should also handle different environments (windows/osx). Being able to clean the repo on a failed install would be handy to prevent unintended errors. Expanding the current gulpfile.js with tasks from package.json would be ideal. For example rm -rf
doesn't work in Windows which is why we have the gulp-rimraf
plugin
Copy over from angular/angular
What's an open-source project without them. Blocked since we need travis
Angular 2 now is able to run on the server so what's the next step?
We can now take advantage of the benefits of having this control over the client's environment. We can create a small server layer that uses any of the underlying Node Frameworks such as ExpressJS, Hapi.js, or Koa.js. Doing so would be a great way for, normally client only developers, to be introduced to the backend.
Having full control over the client's environment allows us to dramatically improve the developer experience with features such as:
import
s for each file (like Rails)prior art
https://github.com/yahoo/fluxible
https://muut.com/riotjs
https://github.com/astoilkov/jsblocks
https://github.com/linnovate/mean
https://github.com/meteor/meteor
https://github.com/rails/rails
https://github.com/django/django
https://github.com/playframework/playframework
https://github.com/elierotenberg/react-nexus
https://github.com/facebook/relay
the Universal app is <app>
while the Server app is the html document itself that we can call an <html>
component.
<html>
<head>
<title>Fullstack Angular 2</title>
<meta></meta>
</head>
<body>
<app></app>
<!-- app-scripts -->
</body>
</html>
currently <doctype>
needs to be injected after the fact
code samples
https://gist.github.com/gdi2290/efa2061467c92243ca58
https://gist.github.com/gdi2290/f07fd579c6ec911d2305
https://gist.github.com/gdi2290/7c2280655dbf50450444
modules:
mincer
RxJS Next
polyfills
bunyan
vantage
webpack
webpack-require
autopolyfiller
After we have Karma working we need to move the preboot.js tests to run in it
built on top of preboot.js, pre-compile a mini angular for server view to recreate actions where the code path doesn't hit a call to the server or 3rd party module. The goal is to allow features such as two-way data binding and simple functionality such as NgIf
stages (may need more research and/or exploratory programming)
At the moment travis us running gulp test rather than npm test
support stream rendering on the server to client
There are a few best practices for web mobile development and one of them is streaming the HTML down to the client. Also consider movements such as JSON.stringifyAsync
which brings up the same point of sending the results. We could stream down the serialized server rendered app via
stringifyElement
=> stringifyElementAsync
attach toString
to ApplicationRef
that serializes the App
toString(): string
disposeToString(): string
NodeXhr only works with the full url not relative
It would be great if we had everything in TypeScript
webpack is a good idea since we want to convert preboot to use it. currently the build system is tsc
cli itself
The router needs to be able to run on the server. History and other services needs to be replaced with Server versions. First let's create a version that works using the Mock version before converting it.
Similar to #50
Create a subclass of angular's DomRenderer
that has special handling for setElementProperty
and invokeElementMethod
, so that the state of the UI is completely contained within attributes of elements. With that, serializing the DOM at the end of processing it via angular is just a matter of serializing the DOM nodes. I.e. we can reuse the existing DOM adapters of Angular.
E.g.
setElementProperty
should translates changes to properties to changes to attributes. E.g.
value
on an input
should set the attribute value
on the element.checked
on input
with a boolean should add/remove the checked
attribute on the elementinvokeElementMethod
should also translate methods into changes to attributes. E.g.
focus
should result in adding the attribute autofocus
to this element and removing the attribute from the previously focussed one.Notes:
parse5
but use the DOM
adapter instead. With this, we can make this work even for Dart...configuration is not clear. We have configuration living in task file and gulpfile. Having configurations in place place would allow for simpler reasoning on each moving part. Having a task per file limits the ability to compose multiple tasks. The repo doesn't need this level of abstraction just yet and would benefit more by having one gulpfile either requiring the configuration or keeping it inline
we should have an experimental/ folder for unstable experiments
figure out a better way to manage installing in travis
we should keep custom typings in custom_typings/
folder and reinstall tsd typings in tsd_typings/
It will be a good idea to have a Test Runner like Karma for testing Server. Include Karma with a unit test in the test folder
given an html element
<input value="testing" autofocus [value]="value" (keyup)="value = $event.target.value">
the cursor position is at the beginning [|testing]
for server rendered view. Then preboot.js transfers the focus back [testing|]
the cursor position is now the latest position and value. Also note that angular doesn't save the cursor position when a user types in a new value. This probably due to setting the [value]
on keyup
this replaces build_scripts.ts
prior art:
riot/compiler
create directives that emulates <module import="angular2/angular2"><module>
and also allow inline scripts such as
<script type="text/typescript">
class App {}
</script>
and also inject dep angular with type="angular"
<module type="angular">
@Component({ selector: 'app' })
@View({ template: '<div>hello world</div>' })
class App {}
</module>
we can also inject systemjs and es6 module loader.
We should also allow for app state management from build_scripts
where we are able to control how the application is ran on the client. Or leave that feature for another module such as ngAppState
<ng-component>
element
<ng-component name="app">
<style>
</style>
<template view="app">
</template>
<module>
import {Component, View} from '@angular/angular';
@Component({
})
@View({
})
class App {
constructor() {
}
}
</module>
<ng-component>
What's an open-source project without travis
The app needs to be able to work with JavaScript turned off. This is to allow older browsers (legacy) to function or large enterprise companies with crazy restrictions. Currently the links should be able to work with no problem. formDirectives(server)
this is done via action
attribute in the <form>
tag which makes a post request
<form>
tags with action
and method
attributesdecouple the current toString
rendering process
prior art:
yahoo/fluxible
init:
request:
We need a way to test different states of the application and to configure it globally via url which is shared between both environments
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.