Universal JavaScript ? SOHO (Jerry-Hong)
Universal JavaScript ?
Universal JavaScript • Isomorphic JavaScript • Isomorphic JavaScript Single Page Application Client Server SPA • Universal JavaScript Isomorphic JavaScript • Single Page Application
Single Page Application (SPA) • (User Experience) • • AJAX, Client-Side Render, Client-Side Router • Gmail, kkbox web player
Server-rendered Server-rendered + AJAX SPA Load Performance Dev Effort User Experence From: How instagram.com Works
SPA
SPA
1.
2.
•
class MyTitle extends Component { render() { return ( <h1>Hello World</h1> ); } } React
Vue.component('my-title', { render(h) { return ( <h1>Hello World</h1> ); } }) Vue 2 (JSX)
Vue.component('my-title', { template: '<h1>Hello World</h1>' }) Vue 2
@Component({ selector: 'my-title', template: '<h1>Hello World</h1>' }) class MyTitle { } NG 2
• • • Flux • Redux • Vuex • CSS class scope • CSS module • web component • vue style scpoed • View • Server-Side Render • Native app
• • • Flux • Redux • Vuex • CSS Class Scope • CSS module • web component • vue style scpoed • View • Server-Side Render • Native app
• • • Flux • Redux • Vuex • CSS class scope • CSS module • web component • vue style scpoed • View • Server-Side Render • Native app . . .
2.
3. SEO Universal JavaScript 4. First Time Loading
Universal JavaScript - React / Redux
• SPA Server Template Engine • SPA Function (F)
F(n)
F(n) => HTML
• SPA Server Client Server • Function (F) • request F HTML • request Client SPA
SPA Universal JS?
• (1~ 5) • •
Universal JS -
Step 1. Router
app .use(compress()) .use(serve('./static'))) .use(router.routes()) .use(serverRender) .use(errorBoot) .listen(process.env.PORT || 8080, () => { console.log('listen 3000') }); Step 1 - Router • Server Router API
app .use(compress()) .use(serve('./static'))) .use(router.routes()) .use(serverRender) .use(errorBoot) .listen(process.env.PORT || 8080, () => { console.log('listen 3000') }); Step 1 - Router • Server Router API • Server Render
const store = createStore(); const childRoutes = createRoute(store); match({ routes: childRoutes, location: ctx.request.url }, (error, redirectLocation, renderProps) => { if (error) { // 500 } else if (redirectLocation) { // 300 } else if (renderProps) { const component = ( <Provider store={ store }> <RouterContext { ...renderProps }/> </Provider> ); const content = ReactDOMServer.renderToString(component); ctx.response.type = 'text/html'; ctx.body = `<!DOCTYPE html> ... ${content}...</html>` } });
app .use(compress()) .use(serve('./static'))) .use(router.routes()) .use(serverRender) .use(errorBoot) .listen(process.env.PORT || 8080, () => { console.log('listen 3000') }); Step 1 - Router • Server Router API • Server Render •
Step 2. AJAX • SPA ComponentDidMount AJAX • Server Render ComponentWillMount Render • Server Render AJAX Response Render
Step 2. AJAX • • Server Render • redux-async-connect • async-props • React-Router onEnter API ( ) • universal-router
@fetchData((dispatch, state, routeState, replace) => { return dispatch(getAllArticle()); }) class Home extends Component { ... } // fetchData(...)(Home)
<Route component={ App }> <Route path="/" component={ Home } onEnter={ Home.onEnter(store) }/> </Route>
// fetchData.js export default fetchCall => Component => { Component.onEnter = (store) => (nextState, replace, callback) => { const result = fetchCall( store.dispatch, store.getState(), nextState, replace) || Promise.resolve(true); if(typeof window === 'undefined') { result.then(() => callback()) .catch((error) => callback(error)) } else { callback(); } } return Component; }
Step 3. • Server Render HTML JS Client Render Client Render
Step 3. • • Server Render HTML • Client Render (initialState)
const store = createStore(); const childRoutes = createRoute(store); match({ routes: childRoutes, location: ctx.request.url }, (error, redirectLocation, renderProps) => { ... ctx.body = `<!DOCTYPE html> ... ${content}... <script> window.reduxState = ${JSON.stringify(store.getState())
 </script> </html>` });
Step 4. • SPA webpack JS • css-loader • url-loader • NodeJS
Step 4. • • webpack bundle server code ( ) • js • • CSS Module css-modules-require-hook
var nodeExternals = require('webpack-node-externals'); ... module.exports = { ... target: 'node', externals: [nodeExternals()] ... }; Step 4 - Bundle node • target node • webpack-node- externals hint: context
Step 5. • Server Client • webpack
new webpack.DefinePlugin({ 'process.env.BROWSER': true })) new webpack.DefinePlugin({ 'process.env.BROWSER': false })) webpack-server.config.js webpack.config.js

 Universal JavaScript

 SEO First Time Loading
Universal JavaScript MVC View
• MVC View • HTML • Universal JavaScript • Client SPA View
Critical Render Path
CSS Critical Render Path • CSS • Style head CSS • • Universal JavaScript
Universal JavaScript • isomorphic-style-loader • Render style head for react-router: https://goo.gl/PYYoLL
...
CSS Secret Lea Verou CSS in JS ? http://www.ituring.com.cn/article/261344
– Lea Verou, CSS Secret If all you have is a hammer, everything looks like a nail.
Lea Verou


JavaScript 3D
HTML CSS 3D
CSS-Module
React-Native
3D
Universal JavaScript
Q&A

Universal JavaScript