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
BigC tutorial part II
- 570