Upload
-
View
1.042
Download
0
Embed Size (px)
Citation preview
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
•
•
• 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
.
.
.
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; }
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>` });
var nodeExternals = require('webpack-node-externals'); ... module.exports = { ... target: 'node', externals: [nodeExternals()] ... };
Step 4 - Bundle node
• target node
• webpack-node-externals
hint: context
new webpack.DefinePlugin({ 'process.env.BROWSER': true }))
new webpack.DefinePlugin({ 'process.env.BROWSER': false }))
webpack-server.config.js webpack.config.js
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