code: https://github.com/MSChuan/Blog-UI,
demo: https://mschuan.github.io/Blog-UI/dist_prod/index.html
从零搭建个人博客(1)-webpack环境配置
代码目录
架构代码
首先是入口文件index.js:
import { initialState } from './helper/ConstantsHelper';
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { browserHistory } from 'react-router';
import { AppContainer } from 'react-hot-loader';
import configureStore from './root/configureStore';
import Root from './root/Root';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './style/main.scss';
const store = configureStore();
render(
<AppContainer>
<Root store={store} />
</AppContainer>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./root/Root', () => {
const NewRoot = require('./root/Root').default;
render(
<AppContainer>
<NewRoot store={store} />
</AppContainer>,
document.getElementById('root')
);
});
}
css文件就是在入口文件这里引入。这里还用到了react-hot-loader,他和普通热加载不同的是可以保持react state不变,方便调试react代码。configureStore用于创建store,有两个版本的代码,在开发环境下configureStore.dev.js:
export default function configureStore(initialState) {
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunk),
DevTools.instrument()
)
);
return store;
}
而在发布版本时使用configureStore.prod.js:
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk),
);
}
可以看到少了调试工具DevTools,最后统一入口,使用configureStore.js:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./configureStore.prod');
} else {
module.exports = require('./configureStore.dev');
}
同样的道理,我们实现了两份Root,打包时只会根据环境打包其中的一个,不会增加代码量。Root.dev.js:
export default class Root extends Component {
render() {
const { store } = this.props;
return (
<Provider store={store}>
<div>
<Routes />
<DevTools />
</div>
</Provider>
);
}
}
Provider是React-redux提供的组件,用于将store通过context传给所有的container。Routes实现了前端路由,实现在routes.js中
export default class Routes extends React.Component {
render() {
return (<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>);
}
}
这是最新的”react-router”: “^4.1.1”的使用方式,老版本中使用了react-router封装的Router组件,需要传入两个props
<Router history={browserHistory} routes={routes} />
routes内部实现为:
<Route>
<Route path="/" component={App}>
</Route>
</Route>
对比后可以发现BrowserRouter封装了browserHistory。这里的App就是入口组件,所有的UI结构都在该组件内。
React-bootstrap
React-boostrap库将bootstrap的组件都用React实现了一遍,在App.js中引入相关组件
import React, { PropTypes } from 'react';
import { Grid, Col, Navbar, Nav, NavItem } from 'react-bootstrap';
实现最顶层的App组件:
class App extends React.Component {
render() {
const {children} = this.props;
return (<Grid id="WorkspaceContainer">
<Col sm={12}>
<div id="TopBarContainer">
<span>欢迎</span>
</div>
</Col>
<Col sm={12}>
<div id="TopImageBarContainer">
<div id="LogoContainer"></div>
<div id="BlogTitleContainer">
<p>WordPPT哥的个人博客</p>
<p>进击的攻城狮,程序猿</p>
</div>
</div>
</Col>
<Col sm={12}>
<Navbar inverse collapseOnSelect>
<Navbar.Header>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav id='NavBarContainer'>
<NavItem eventKey={1} href="#">首页</NavItem>
<NavItem eventKey={2} href="#">技术分享</NavItem>
<NavItem eventKey={3} href="#">生活点滴</NavItem>
<NavItem eventKey={4} href="#">留言板</NavItem>
</Nav>
</Navbar.Collapse>
</Navbar>
</Col>
<Col sm={3}>
<div id="LeftAreaContainer">Placeholder</div>
</Col>
<Col sm={9}>
<div id="RightAreaContainer">{children}</div>
</Col>
</Grid>);
}
}
Grid组件是bootstrap响应式布局的Container,将可用宽度分为12份,意味着占满整个宽度。Navbar的下面有两个部分,左边区域较小,占了3份,右边区域占了9份,{children}可以根据router显示不同的组件。