ݺߣ

ݺߣShare a Scribd company logo
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.
Universal JavaScript
?
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?
Universal JavaScript
Universal JavaScript
Universal JavaScript
Universal JavaScript
Universal JavaScript
? (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.con?g.js webpack.con?g.js
?
Universal JavaScript
?
SEO First Time Loading
Universal JavaScript
MVC View
? MVC View
? HTML
? Universal JavaScript
? Client SPA View
Critical Render Path
Universal JavaScript
Universal JavaScript
Universal JavaScript
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
Universal JavaScript
Universal JavaScript
Universal JavaScript
...
CSS Secret Lea Verou
CSS in JS ?
http://www.ituring.com.cn/article/261344
C 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

More Related Content

Universal JavaScript