BIG C Project

Toturial part II

Agenda

  • 系統架構
  • 程式架構
  • Redux 教學
  • Backend Service
  • Router
  • CSS Resolution

系統架構

System Architecture

程式架構

Software Architecture

Overview

  • Express Server
  • Isomorphic rendering
  • Babel6 for ES6 & ES2015
  • React - Redux
  • React-router for routing
  • Webpack for bundling
  • Editing hot-reload
  • Only one node server process
  • Css modules for local css
  • Json-LD for meta information

Write once, run anywhere

Learn once, run anywhere

開發環境部屬

Clone repo from git

change to project repo

install

Run Client ( for develope)

Build ( only for production )

$npm install
$npm run dev
$npm run build
$cd redux-startkit
https://github.com/rexhome7326/redux-startkit

Server Flow

Total Data Flow

React Library

Router

React-router

  <Router>
    <Route path="/" component={App}>
      {/* Show the dashboard at / */}
      <IndexRoute component={Dashboard} />
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>

Basic use

History-npm

HTML5 history API

  • createHashHistory
  • createBrowserHistory
  • createMemoryHistory ( only for test )
  • push(location)
  • replace(location)
  • go(n)
  • goBack()
  • goForward()

History method

this.props.history.method()
import createBrowserHistory from 'history/lib/createBrowserHistory';

const history = createBrowserHistory();

<Router history={history}>
    <Route path="/" component={App}>
    </Route>
</Router>

Using History

Need DOM node =>

  • Only use on client 
  • ComponentDidMount
app.use((req, res, next) => {
    let history = createMemoryHistory();
    let routes = pageRoutes(history);
    let location = createLocation(req.url);
    match({ routes, location }, (error, redirectLocation, renderProps) => {
        if (redirectLocation) {
            res.redirect(301, redirectLocation.pathname + redirectLocation.search)
        } else if (error) {
            res.status(500).send(error.message);
        } else if (renderProps == null) {
            res.status(404).send('Not found');
        } else {
	    res.status(200).send(renderToString(<RouterContext {...renderProps} />))			
	}
    });
});

Status routing

CSS Modules

React CSS Resolution

Before..

Traditional CSS:

  • css by page  需要引入很多css檔案
  • 模組化困難、重用性低
  • 上線前需要壓縮的程序
  • css命名易衝突 (Global namespace)
  • 階層過多降低效率

SASS..

很好很強大..但仍有以下問題

  • import file 目錄結構複雜
  • 仍然有Global namespace的問題
  • 需要另外起compiler且效能低落
  • 可怕的巢狀命名,編譯出來的code效能慘烈
  • 有很多很好的撰寫規範...可是最後發現沒有人在遵守

CSS in JS

  • Component with style
  • object syntax
  • inline style kill everything
  • make CSSer crazy

POSTCSS

POST-processor : just write css

Plugin

  • auto-prefixer  自動加上瀏覽器前綴
  • cssnext  使用css4等下世代的css語法
  • stylelint  幫你找出不好的css寫法
  • doiuse   檢查css語法在瀏覽器上的支援度
  • CSS Modules

Plugins :

Local CSS

假如我們今天要有一個button擁有四種狀態

而在不同的頁面又有不同的顏色的話,CSS該怎麼寫呢?

In SCSS

.button{
    //button 共用屬性
    &.button-special { 
        //button-special 共用屬性
        &.normal { ... }
        &.disabled { ... }
        &.touched { ... }
    }
    &.button-normal {
        //button-normal 共用屬性
        &.disabled { ... }
    }
}
.PageA{
    .button { ... }
    .button-special { ... }
    .button-normal { ... }
}
.PageB{
    .button { ... }
    .button-special { ... }
    .button-normal { ... }
}

button.scss

page.scss

CSS modules

.button{
    //button 共用屬性
}
.normal { ... }
.disabled { ... }
.touched { ... }

button.css

//依據使用者行為切換state狀態
return(
    <button styleName="button 
                     { this.state.buttonState }">
    </button>
)

button.jsx

MIXIN/EXTEND?

Using compose

.common { /* font-sizes, padding, border-radius */ }
.normal { composes: common; /* blue color, light blue background */ }
.error { composes: common; /* red color, light red background */ }

.components_submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }
.components_submit_button__normal__def6547 { /* blue color, light blue background */ }
.components_submit_button__error__1638bcd { /* red color, light red background */ }

Benefit

  • Local NameSpace
  • Component with Style, no interrupt
  • No fxxking slow Compiler
  • Less CSS rule to follow
  • Class naming is very easy

BUT....

Thinking

In

CSSModules Way

Is

REALLY HARD

SO....

  • Re-structuring your old css code
  • Have good web component thinking
  • separate CSS into Global and Local

 

  • ASK PARTNER
  • CODE REVIEW 

Usage

Install

{
    test: /\.css$/,
    loader: "style-loader!css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]",
    include: __dirname
}

Loader

npm install style-loader --save-dev
npm install css-loader --save-dev
npm install react-css-modules --save-dev
npm install css-module-require-hook --save-dev

Require-hook ( for isomorphic )

import CSSModules from 'react-css-modules';

export default connect(mapStateToProps, { loadDemo })(CSSModules(Demo,style));

Composed component

( using styleName syntax )

hook({
    generateScopedName: '[name]__[local]___[hash:base64:5]',
});

We commend :

Using  <className="name"> for Global CSS

Using <styleName="name"> for LOCAL CSS

BigC tutorial part II

By Derek silenceshia