typescript+react+antd基础环境搭建(包含样式定制)
- tsconfig.json 配置
// 具体配置可以看上面的链接 这里module moduleResolution的配置都会影响到antd的显示
// allowSyntheticDefaultImports 是antd官网给的配置 必须加上
{
\"compilerOptions\": {
\"outDir\": \"./dist/\",
\"sourceMap\": false,
\"noImplicitAny\": false,
\"module\": \"es6\",
\"target\": \"es5\",
\"jsx\": \"preserve\",
\"moduleResolution\": \"node\",
\"forceConsistentCasingInFileNames\": false,
\"allowJs\": true,
\"allowSyntheticDefaultImports\": true,
\"lib\": [
\"es5\",
\"dom\",
\"dom.iterable\",
\"es2015\"
]
},
\"include\": [
\"./src/**/*\"
]
}
- package.json 配置
// 其中很多配置是用来做antd样式定制的
// concurrently 是用来将命令连接起来执行的 Run multiple commands concurrently
{
\"name\": \"power3\",
\"version\": \"1.0.0\",
\"description\": \"typescript && react for power3\",
\"main\": \"index.js\",
\"scripts\": {
\"build\": \"webpack --progress --colors\",
\"start\": \"concurrently \\\"node ./server/server.js\\\" \\\" npm run dev \\\"\",
\"dev\": \"webpack-dev-server --progress --colors -p -d\"
},
\"author\": \"\",
\"license\": \"ISC\",
\"dependencies\": {
\"antd\": \"^2.13.6\",
\"css-loader\": \"^0.28.7\",
\"immutable\": \"^3.8.2\",
\"md5\": \"^2.2.1\",
\"react\": \"^15.5.4\",
\"react-dom\": \"^15.5.4\",
\"react-hot-loader\": \"^3.1.1\",
\"react-router\": \"^4.2.0\",
\"react-router-dom\": \"^4.2.2\"
},
\"devDependencies\": {
\"@types/node\": \"^8.0.34\",
\"@types/react\": \"^16.0.10\",
\"@types/react-dom\": \"^16.0.1\",
\"@types/react-router\": \"^4.0.15\",
\"@types/react-router-dom\": \"^4.0.8\",
\"awesome-typescript-loader\": \"^3.2.3\",
\"babel-core\": \"^6.26.0\",
\"babel-loader\": \"^7.1.2\",
\"babel-plugin-import\": \"^1.6.2\",
\"babel-preset-env\": \"^1.6.1\",
\"babel-preset-react\": \"^6.24.1\",
\"babel-preset-stage-0\": \"^6.24.1\",
\"concurrently\": \"^3.4.0\",
\"extract-text-webpack-plugin\": \"^2.1.0\",
\"html-webpack-plugin\": \"^2.30.1\",
\"less\": \"^2.7.2\",
\"less-loader\": \"^4.0.5\",
\"less-vars-to-js\": \"^1.2.0\",
\"source-map-loader\": \"^0.2.2\",
\"style-loader\": \"^0.19.0\",
\"typescript\": \"^2.5.3\",
\"url-loader\": \"^0.5.8\",
\"webpack\": \"^2.3.3\",
\"webpack-dev-server\": \"^2.4.2\",
\"webpack-hot-middleware\": \"^2.20.0\"
}
}
- routes.tsx页面
该页面主要用来配置路由 指定登录页面
推荐使用react-router-dom 里面的各种接口直接继承感觉很方便
/**
* 路由写到此处 页面一般会有层级关系 此处json对象是按照业务写成层级关系
* 第一种做法是 处理成 平级的路由
* 第二种是 根据业务的层级关系渲染出符合业务的相应导航
* 此处两种都导出 然后在index.tsx中可以两种都试一下
*/
import {RouteProps} from \'react-router-dom\'
import Apple from \'./components/fruits/Apple\'
import Banana from \'./components/fruits/banana\'
import Cabbage from \'./components/vegetables/cabbage\'
import Radish from \'./components/vegetables/radish\'
interface PowerRouteProps extends RouteProps{
name:string;
}
export const _routes=[
{
id:\'fruits\',
name:\'水果\',
routes:[
{
name:\'苹果\',
path:\'/apple\',
component:Apple
},
{
name:\'香蕉\',
path:\'/banana\',
component:Banana
}
]
},
{
id:\'vegetables\',
name:\'蔬菜\',
routes:[
{
name:\'白菜\',
path:\'/cabbage\',
component:Cabbage
},
{
name:\'萝卜\',
path:\'/radish\',
component:Radish
}
]
}
];
// 此处变量我之前使用 routes 命名 结果在index.tsx引入时(import {routes} from \'./routes\') 直接报错
// 注意导出变量名和文件名不能一样
export const maproutes = _routes.reduce((ary:PowerRouteProps[],cur:any)=>{
return ary.concat(cur.routes||cur)
},[]).filter(x=>x.path && x.path!==\'\');
- 简单的业务组件(只为了说明)
其他的组件可以在github上看
// ./components/vegetables/cabbage
import * as React from \'react\'
export default class Cabbage extends React.Component{
render(){
return (<p>You need to eat cabbage</p>)
}
}
- 入口文件index.tsx
此处写了两种导航 一种有submenu 一种是使用plain数据直接将所有路由列出
import * as React from \'react\'
import * as ReactDOM from \'react-dom\'
import {HashRouter, Route, Switch, Link, BrowserRouter} from \'react-router-dom\'
// 提供antd的本地语言支持
import {LocaleProvider, Menu} from \'antd\'
const MenuItem = Menu.Item;
const SubMenu = Menu.SubMenu;
import {maproutes,_routes} from \'./routes\'
// plain 路由
class Navigation extends React.Component {
render() {
return (
<Menu>
{maproutes.map(route => {
return (
<MenuItem key={route.path}>
<Link to={route.path} key={`route-link-${route.path}`}>{route.name}</Link>
</MenuItem>
)
})}
</Menu>
)
}
}
// 有层级关系的路由
class Navigations extends React.Component {
render() {
return (
<Menu style={{width:200}} mode=\"inline\">
{_routes.map(routes=>{
return (
<SubMenu key={routes.id} title={routes.name}>
{routes.routes.map(route=>{
return (
<MenuItem key={`route-${route.path}`}>
<Link to={route.path} key={`route-link-${route.path}`}>{route.name}</Link>
</MenuItem>
)
})}
</SubMenu>)
})}
</Menu>
)
}
}
class NotFoundView extends React.Component {
render() {
return (
<div className=\"http-404\">
<h2 className=\"text-info\">功能尚未开发完毕</h2>
<h3 className=\"text-danger\">Page not found</h3>
</div>
);
}
}
const Router = () => (
<BrowserRouter>
<Switch>
{maproutes.map(route => {
// return <Route path={route.path} key={`route-path-${route.path}`} location={route.location} component={route.component}/>
return <Route path={route.path} key={`route-${route.path}`} component={route.component}/>
})}
<Route path=\"/\" exact component={Navigations}/>
<Route component={NotFoundView}/>
</Switch>
</BrowserRouter>
)
ReactDOM.render(
<Router/>, document.getElementById(\'app\'));
- 样式定制(使用社区提供的方法)
创建.babelrc文件
在终端(ctrl+`)中输入 type null>.babelrc
.babelrc文件
plugins的配置是为了让antd的样式生效
{
\"presets\": [
[\"env\"],
\"stage-0\",
\"react\"
],
\"plugins\": [
\"react-hot-loader/babel\",
[\"import\", { \"libraryName\": \"antd\",\"style\": true}]
]
}
- 最后一步 webpack.config.js文件编写
const webpack = require(\'webpack\');
const ExtractTextPlugin = require(\'extract-text-webpack-plugin\');
const HtmlWebpackPlugin = require(\'html-webpack-plugin\');
const path = require(\'path\');
const fs = require(\'fs\');
const lessToJs = require(\'less-vars-to-js\');
// 获取自己定义的要覆盖antd默认样式的文件
const themeVariables = lessToJs(fs.readFileSync(path.join(__dirname, \'./src/assets/style/themes.less\'), \'utf8\'));
module.exports = {
entry: \"./src/index.tsx\",
output: {
filename: \"bundle.js\",
path: __dirname + \"/dist\"
},
// Enable sourcemaps for debugging webpack\'s output.
devtool: \"cheap-moudle-source-map\",
resolve: {
// Add \'.ts\' and \'.tsx\' as resolvable extensions.
extensions: [\".ts\", \".tsx\", \".js\", \".json\"]
},
devServer: {
port: 8003,
hot: true,
// historyApiFallback: true,
historyApiFallback: {
index: \'/react.min.js\'
},
contentBase: path.resolve(__dirname, \'dist\'),
publicPath: \'/\'
},
module: {
rules: [
// All files with a \'.ts\' or \'.tsx\' extension will be handled by
// \'awesome-typescript-loader\'.
{
test: /\\.(tsx|ts)?$/,
use: [
{
loader: \'react-hot-loader/webpack\'
}, {
loader: \'babel-loader\'
}, {
loader: \'awesome-typescript-loader\'
}
]
},
// All output \'.js\' files will have any sourcemaps re-processed by
// \'source-map-loader\'.
{
enforce: \"pre\",
test: /\\.js$/,
loader: \"babel-loader\",
exclude: /node_modules/
}, {
test: /\\.less$/,
use: [
{
loader: \"style-loader\"
}, {
loader: \"css-loader\"
}, {
loader: \"less-loader\",
options: {
modifyVars: themeVariables
}
}
]
}, {
test: /\\.css$/,
use: ExtractTextPlugin.extract({fallback: \'style-loader\', use: \'css-loader\', publicPath: \'/\'})
}, {
test: /\\.(png|jpg|jpeg|gif|svg)$/,
loader: \'url-loader?limit=8192&name=[name].[ext]&publicPath=\'
}
]
},
// When importing a module whose path matches one of the following, just assume
// a corresponding global variable exists and use that instead. This is
// important because it allows us to avoid bundling all of our dependencies,
// which allows browsers to cache those libraries between builds.
externals: {
// \"react\": \"React\",
// \"react-dom\": \"ReactDOM\"
},
plugins: [
new HtmlWebpackPlugin({
template: \'./src/index.html\',
title: \'hello ts&react\',
inject: false,
minify: {
removeComments: true,
collapseWhitespace: true
},
chunksSortMode: \'dependency\'
}),
new ExtractTextPlugin({filename: \'[name].css\', allChunks: true}),
new webpack.HotModuleReplacementPlugin()
]
};
// 此处是借鉴同事的 啊哈哈哈
const os = require(\'os\');
console.log(`############################################################################`);
console.log(`## os: ${os.type()} ${os.arch()} ${os.release()}`);
console.log(`## ram: ${ (os.freemem() / 1024 / 1024 / 1024) < 1
? (os.freemem() / 1024 / 1024).toFixed(0) + \'MB\'
: (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + \'GB\'}`);
console.log(`## time: ${new Date()}`);
console.log(`############################################################################`);
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。



