2016 JSDC Topic: Universal JavaScript
Universal JavaScript ?肬禂 SOHOෟ螲᪠螂 ၒݷ蜤(Jerry-Hong)
View Slide
Ջ讕ฎ 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 SPALoad PerformanceDev EffortUser ExperenceFrom: How instagram.com Works
匍ࣁ獮ᒒૡ纷䒍᮷ᥝٍ猋 SPA ጱ樄咳妿涢
螭䷱樄咳螂 SPA 䌕礯牧皃㮆ଉ憎ጱܻࢩ
1. 襑穩犋ᒧ嘦䋿礓犚觊ࣳጱ䌕礯犋螕ݳ
2. 獮ᒒದ蔩虋矦ॡ盠牧犋Ꭳ螇ᥝ䋊ߺӞॺ牦
䋿褬Ӥ匍ࣁ獮ᒒ礍ጱݶ搡玕纷ଶ᩼㬵᩼ṛ牦
• زկ玕
class MyTitle extends Component {render() {return (Hello World);}}React زկ
Vue.component('my-title', {render(h) {return (Hello World);}})Vue 2 زկ(JSX)
Vue.component('my-title', {template: 'Hello World'})Vue 2 زկ
@Component({selector: 'my-title',template: 'Hello World'})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 JavaScript4. 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 = ();const content = ReactDOMServer.renderToString(component);ctx.response.type = 'text/html';ctx.body = ` ... ${content}...
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)
path="/"component={ Home }onEnter={ Home.onEnter(store) }/>
// fetchData.jsexport 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 = ` ... ${content}...<br/>window.reduxState = ${JSON.stringify(store.getState()) <br/>
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-externalshint:ᥝ戔ਧ 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 㪔लک headfor 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