转载请注明出处!php
一、为何不使用现成的脚手架?脚手架配置的东西太多过重了,一股脑全塞给你,我只想先用一些我能懂的库和插件,而后慢慢的添加其余的。并且本身从零开始配置也能学到更多的东西不是么。css
二、教程只配置了开发环境,并无配置生产环境。html
三、教程针对人群是有过React + Redux经验,而且想在新项目中使用TypeScript的人(或者是想本身从零开始配置开发环境的)前端
四、由于前端发展突飞猛进,今天能用的配置到明天可能就不能用了(好比React-Router就有V4了,并且官方说是彻底重写的),因此本文中安装的包都是指定版本的。node
五、教程遵循最小可用原则,因此能不用的库和插件就没用(主要是会的就没多少,怕用出问题,逃~~)。react
六、基于5,因此教程不会一开始就把全部东西全装上,会一步一步慢慢来。webpack
六、教程在macOS下完成,win环境系可能会有一些其余的问题。git
node版本为6.9.0es6
建立并进入项目github
mkdir demo && cd demo
初始化项目
npm init
首先是安装webpack和webpack-dev-server(全局安装过的请忽略)
npm i -D webpack@3.6.0
而后安装React和Types中React的声明文件
npm i --S react@15.5.4 react-dom@15.5.4 @types/react@15.6.0 @types/react-dom@15.5.0
上面@types开头的包都是typeScript的声明文件,你能够进入node_modules/@types/XX/index.d.ts进行查看。
关于声明文件的具体介绍能够在github上的DefinitelyTyped库看到。
接下来安装TypeScript,ts-loader和source-map-loader
npm i -D typescript@2.5.3 ts-loader@2.3.7 source-map-loader@0.2.2
ts-loader可让Webpack使用TypeScript的标准配置文件tsconfig.json编译TypeScript代码。
source-map-loader使用任意来自Typescript的sourcemap输出,以此通知webpack什么时候生成本身的sourcemaps。 这让你在调试最终生成的文件时就好像在调试TypeScript源码同样。
咱们须要一个tsconfig.json文件来告诉ts-loader如何编译代码TypeScript代码。
在当前根目录下建立tsconfig.json文件,并添加以下内容:
{ "compilerOptions": { "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es5", "jsx": "react" }, "include": [ "./src/**/*" ] }
outDir:输出目录。
sourceMap:把 ts 文件编译成 js 文件的时候,同时生成对应的sourceMap文件。
noImplicitAny:若是为true的话,TypeScript 编译器没法推断出类型时,它仍然会生成 JavaScript 文件,可是它也会报告一个错误。为了找到错误仍是设置为true比较好。
module:代码规范,也能够选amd。
target:转换成es5
jsx:TypeScript具备三种JSX模式:preserve
,react
和react-native
。 这些模式只在代码生成阶段起做用 - 类型检查并不受影响。 在preserve
模式下生成代码中会保留JSX以供后续的转换操做使用(好比:Babel)。 另外,输出文件会带有.jsx
扩展名。 react
模式会生成React.createElement
,在使用前不须要再进行转换操做了,输出文件的扩展名为.js
。 react-native
至关于preserve
,它也保留了全部的JSX,可是输出文件的扩展名是.js
。咱们这里由于不会用babel再转,因此用react就行。
include:须要编译的目录。
首先建立目录
mkdir src && cd src
mkdir components && cd components
在此文件夹下添加一个Hello.tsx文件,代码以下:
import * as React from 'react'; export interface Props { name: string; enthusiasmLevel?: number; } export default class Hello extends React.Component<Props, object> { render() { const { name, enthusiasmLevel = 1 } = this.props; if (enthusiasmLevel <= 0) { throw new Error('You could be a little more enthusiastic. :D'); } return ( <div className="hello"> <div className="greeting"> Hello {name + getExclamationMarks(enthusiasmLevel)} </div> </div> ); } } function getExclamationMarks(numChars: number) { return Array(numChars + 1).join('!'); }
接下来,在src
下建立index.tsx
文件,代码以下:
import * as React from "react"; import * as ReactDOM from "react-dom"; import Hello from "./components/Hello"; ReactDOM.render( <Hello name="TypeScript" enthusiasmLevel={10} />, document.getElementById('root') as HTMLElement );
咱们还须要一个页面来显示Hello
组件。 在根目录建立一个名为index.html
的文件,以下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>demo</title> </head> <body> <div id="root"></div> <script src="./dist/bundle.js"></script> </body> </html>
在根目录下建立一个名为webpack.common.config.js文件,并添加一下内容:
module.exports = { entry: "./src/index.tsx", output: { filename: "bundle.js", path: __dirname + "/dist" }, devtool: "source-map", resolve: { extensions: [".ts", ".tsx", ".js", ".json"] }, module: { rules: [ { test: /\.tsx?$/, loader: "ts-loader" }, { enforce: "pre", test: /\.js$/, loader: "source-map-loader" } ] }, plugins: [ ], };
这里不作过多的解释了。基本上有webpack经验的都看得懂。至于为何是webpack.common.config.js而不是webpack.config.js。是由于咱们如今要配置的是开发环境,之后须要配置生产环境,因此咱们就须要多个配置文件,而且将这两个的通用部分放入到webpack.common.config.js
在根目录下运行一下命令:
webpack --config webpack.common.config.js
而后打开index.html就能看到咱们写的页面了。
若是是正式作开发,上面的代码确定是不够的,咱们须要webpacl-dev-server提供的最基本也是最好用的热更新功能。
npm i -D webpack-dev-server@2.9.1
在根目录下建立webpack.dev.config.js,并添加如下配置:
const webpack = require('webpack'); const config = require('./webpack.common.config'); config.devServer = { hot: true, publicPath: '/dist/' } config.plugins.push(new webpack.HotModuleReplacementPlugin()); module.exports = config;
首先须要引入公共的配置,而后在基础之上进行修改。
devServer就是webpack-dev-server的配置项。
hot:开启热更新,开启热更新以后,咱们须要在plugins中加入webpack.HotModuleReplacementPlugin来彻底启用。同时官方文档中指出,若是在命令中使用--hot来启动webpack-dev-server的话,就会自动加载这个插件,再也不须要在config.js中进行引入。
关于HMR的相关部分能够点击webpack HMR查看。
publicPath:资源目录,由于webpack-dev-server启动以后会把编译后的资源放在内存当中,那这些资源在哪呢?就是在publicPath指定的目录里,由于咱们在webpack.common.config.js中配置的output.path是当前目录的/dist目录下,为了避免再去更改根目录下的index.html文件,因此咱们这里也设置成/dist/。 这部份内容具体能够参照详解Webpack2的那些路径
运行命令:
webpack-dev-server --config webpack.dev.config.js
打开网页,进入localhots:8080就能够看到咱们的页面了。打开浏览器的开发者工具,在console部分能看到如下两句提示就说明热更新启动成功了,
而后把这部分很长的命令加入到npm scripts。在package.json的scripts下添加 "start": "webpack-dev-server --config webpack.dev.config.js"
输入npm start 就能够开启咱们的服务了。
安装redux的依赖
npm i -S redux@3.7.2 react-redux@5.0.5 @types/react-redux@5.0.6
为了能体现redux,咱们接下来给咱们的网页添加两个按钮来增长/删除文字后面的感叹号。
首先,咱们来建立一个文件来存放store的接口声明,放入src/types/index.tsx中,代码以下:
export interface StoreState {
languageName: string;
enthusiasmLevel?: number;
}
定义一些常量供action和reducer使用,放入src/constants/index.tsx
export const INCREMENT_ENTHUSIASM = 'INCREMENT_ENTHUSIASM'; export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM; export const DECREMENT_ENTHUSIASM = 'DECREMENT_ENTHUSIASM'; export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;
添加action,放入src/actions/index.tsx
import * as constants from '../constants' export interface IncrementEnthusiasm { type: constants.INCREMENT_ENTHUSIASM; } export interface DecrementEnthusiasm { type: constants.DECREMENT_ENTHUSIASM; } export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm; export function incrementEnthusiasm(): IncrementEnthusiasm { return { type: constants.INCREMENT_ENTHUSIASM } } export function decrementEnthusiasm(): DecrementEnthusiasm { return { type: constants.DECREMENT_ENTHUSIASM } }
添加reducer,放入src/reducers/index.tsx
import { EnthusiasmAction } from '../actions'; import { StoreState } from '../types/index'; import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index'; export function enthusiasm(state: StoreState, action: EnthusiasmAction): StoreState { switch (action.type) { case INCREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 }; case DECREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) }; } return state; }
修改一下Hello组件,如下是修改后的代码:
import * as React from 'react'; export interface Props { name: string; enthusiasmLevel?: number; onIncrement?: () => void; onDecrement?: () => void; } export default function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) { if (enthusiasmLevel <= 0) { throw new Error('You could be a little more enthusiastic. :D'); } return ( <div className="hello"> <div className="greeting"> Hello {name + getExclamationMarks(enthusiasmLevel)} </div> <div> <button onClick={onDecrement}>-</button> <button onClick={onIncrement}>+</button> </div> </div> ); } function getExclamationMarks(numChars: number) { return Array(numChars + 1).join('!'); }
此时咱们页面已经修改为功了,但点击没有反应,由于咱们尚未链接到redux的store中。
添加一个container来连接Hello组件,放入src/containers/Hello.tsx中
import Hello from '../components/Hello'; import * as actions from '../actions/'; import { StoreState } from '../types/index'; import { connect, Dispatch } from 'react-redux'; export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) { return { enthusiasmLevel, name: languageName, } } export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) { return { onIncrement: () => dispatch(actions.incrementEnthusiasm()), onDecrement: () => dispatch(actions.decrementEnthusiasm()), } } export default connect(mapStateToProps, mapDispatchToProps)(Hello);
建立一个initState,来定义store初始的值,放入/src/store/initState.tsx中
export default { enthusiasmLevel: 1, languageName: 'TypeScript', }
建立一个store,放入/src/store/configureStore.tsx中
import { createStore } from 'redux'; import { enthusiasm } from '../reducers/index'; import { StoreState } from '../types/index'; import initState from './initState'; export default function () { const store = createStore<StoreState>(enthusiasm, initState); return store; }
最后修改一下入口文件index.tsx
import * as React from "react"; import * as ReactDOM from "react-dom"; import Hello from './containers/Hello'; import { Provider } from 'react-redux'; import configureStore from './store/configureStore'; const store = configureStore(); ReactDOM.render( <Provider store={store}> <Hello /> </Provider>, document.getElementById('root') as HTMLElement );
至此,一个简单的redux就弄好了。能够点击按钮增长/删除感叹号了。
可是如今还有不少不完善的地方,好比Hello组件居然是一个函数,再好比reducer居然只有一个(解决这两个问题的过程当中会有一些bug待咱们解决)。
放心,这些都将在下面的“添加一个够用的Redux”中解决。
很明显,一个简单的redux在咱们稍微大一点的开发中是明显不够用的。
因此咱们来改写一下咱们的代码。
首当其冲的就是咱们的Hello组件。咱们把Hello组件改为class的形式
export default class Hello extends React.Component<Props, {}> { constructor(props: Props) { super(props); } render() { const { name, enthusiasmLevel = 1, onIncrement, onDecrement } = this.props; if (enthusiasmLevel <= 0) { throw new Error('You could be a little more enthusiastic. :D'); } return ( <div className="hello"> <div className="greeting"> Hello {name + getExclamationMarks(enthusiasmLevel)} </div> <div> <button onClick={onDecrement}>-</button> <button onClick={onIncrement}>+</button> </div> </div> ); } }
保存,编译中,而后就报错了!
------------------------------------------------------------------------------------------------
ERROR in ./src/containers/Hello.tsx
(20,61): error TS2345: Argument of type 'typeof Hello' is not assignable to parameter of type 'ComponentType<{ enthusiasmLevel: number; name: string; } & { onIncrement: () => IncrementEnthusia...'.
Type 'typeof Hello' is not assignable to type 'StatelessComponent<{ enthusiasmLevel: number; name: string; } & { onIncrement: () => IncrementEnt...'.
Type 'typeof Hello' provides no match for the signature '(props: { enthusiasmLevel: number; name: string; } & { onIncrement: () => IncrementEnthusiasm; onDecrement: () => DecrementEnthusiasm; } & { children?: ReactNode; }, context?: any): ReactElement<any>'.
------------------------------------------------------------------------------------------------
赶忙复制,而后google一下,就能找到咱们要的答案TypeScript-React-Starter | Issues#29,从别人的回答来看貌似是一个bug?那咱们就按回答来更改一下咱们的Hello容器
export function mergeProps(stateProps: Object, dispatchProps: Object, ownProps: Object) { return Object.assign({}, ownProps, stateProps, dispatchProps); } export default connect( mapStateToProps, mapDispatchToProps, mergeProps)(Hello);
刚改完,还没等保存,IDE就提醒咱们有一个错误:
Property 'assign' does not exist on type 'ObjectConstructor'.
很明显,是由于Object没有assign这个方法,有三种解决方式:
一、安装Object-assign这个npm包,用这个包去替代。
二、在tsconfig.json中把target从"es5"修改成"es6"。
三、在tsconfig.json的compilerOptions中添加属性"lib": [
而后再次编译,发现仍是依旧报错。只不过此次错误信息改了:
------------------------------------------------------------------------------------------------
ERROR in ./src/index.tsx
(10,5): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<Props, "name" | "enthusiasmLevel" |...'.
Type '{}' is not assignable to type 'Readonly<Pick<Props, "name" | "enthusiasmLevel" | "onIncrement" | "onDecrement"> & Object>'.
Property 'name' is missing in type '{}'.
------------------------------------------------------------------------------------------------
此次的报错是在index.tsx中,能够看到是由于在Hello组件咱们定义的接口中name的属性是必须传的,可是在index.tsx中没有显示的传过去。
可是若是你的浏览器是chrome并安装了react插件的话能够看到编译后的代码是有传的
姑且就当作是一个bug吧,解决方案有两种,一种是的index.tsx中给Hello容器加上一个name
ReactDOM.render( <Provider store={store}> <Hello name="123"/> </Provider>, document.getElementById('root') as HTMLElement );
这里就算加上name也仍是直接显示的store中的name。因此咱们这里采用这种方式,而且后面加上React-router以后这段代码就会改掉,就不会有这个问题了。
另外一种是在Hello组件中把name属性改为非必要属性:
export interface Props { name?: string; enthusiasmLevel?: number; onIncrement?: () => void; onDecrement?: () => void; }
这种方式不推荐。
好了,到如今为止组件更改完成了。
接下来咱们解决多个reducer的问题。
首先咱们把initState的默认值更改一下:
export default { demo: { enthusiasmLevel: 1, languageName: 'TypeScript', } }
固然还有/src/types/index.tsx也要更改:
export interface demo { languageName: string; enthusiasmLevel?: number; } export interface StoreState { demo: demo; }
而后讲/src/reducers/index.tsx命名为demo.tsx,并对内容进行修改:
import { EnthusiasmAction } from '../actions'; import { demo } from '../types/index'; import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index'; import initState from '../store/initState'; export function enthusiasm(state: demo = initState.demo, action: EnthusiasmAction): demo { switch (action.type) { case INCREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 }; case DECREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) }; } return state; }
其实就是把对应的接口类型进行了更改,并给state添加了默认值。
而后新建一个index.tsx文件,并添加如下内容:
import { combineReducers } from 'redux'; import { enthusiasm } from './demo'; const rootReducer = combineReducers({ demo: enthusiasm }); export default rootReducer;
相对应的,也须要修改Hello容器中的引用的值:
export function mapStateToProps({ demo: { enthusiasmLevel, languageName } }: StoreState) { return { enthusiasmLevel, name: languageName, } }
最后修改一下configureStore中的引用的reducer:
import { createStore } from 'redux'; import reducers from '../reducers/index'; import { StoreState } from '../types/index'; import initState from './initState'; export default function () { const store = createStore<StoreState>(reducers, initState); return store; }
更改完毕,保存。报错...
------------------------------------------------------------------------------------
ERROR in ./src/store/configureStore.tsx
(6,41): error TS2345: Argument of type 'Reducer<{}>' is not assignable to parameter of type 'Reducer<StoreState>'.
Type '{}' is not assignable to type 'StoreState'.
Property 'demo' is missing in type '{}'.
------------------------------------------------------------------------------------
是否是感受很熟悉,和以前index.tsx中关于Hello组件的报错几乎同样。
这里也有两种解决方案,一种是找到configureStore.tsx中的 const store = createStore<StoreState>(reducers, initState); 把 <StoreState> 泛型删除。
第二种是和以前同样的,找到/src/types/index.tsx,将 demo: demo; 加上一个?使之变为非必须的属性 demo?: demo; 咱们这里就采用这种方法。
这里到底是bug仍是其余什么缘由,但愿有大神能解答。
至此,咱们够用的redux就已经完成了。
须要注意的是,如今react-router已经到了V4版本了,而且官方说这是一个彻底重写的版本。因此在我不太熟悉的状况下,保险起见仍是先选择V3版本,等之后再更新。
安装依赖
npm i -S react-router@3.0.5 @types/react-router@3.0.5
在src目录下建立文件routers.tsx,并添加如下内容:
import * as React from 'react'; import { Route, IndexRoute } from 'react-router'; import Hello from './containers/Hello'; export default ( <Route path="/"> <IndexRoute component={Hello} /> <Route path="/demo"> <IndexRoute component={Hello} /> </Route> </Route> );
为了显示路由的做用,就加了一个demo路径。
而后在index.tsx中加上咱们的路由
import * as React from "react"; import * as ReactDOM from "react-dom"; import { Provider } from 'react-redux'; import configureStore from './store/configureStore'; import { Router, browserHistory } from 'react-router'; import routes from './routes'; const store = configureStore(); ReactDOM.render( <Provider store={store}> <Router history={browserHistory} routes={routes} /> </Provider>, document.getElementById('root') as HTMLElement );
因为咱们添加的是browserHistory做为路由,不是hashHistory,因此咱们须要对服务器作一些路由配置才行。至于为何,请自行搜索,这里不作说明了。若是不想用过多设置,也能够直接把browserHistory替换为hashHistory便可。
这里咱们的开发服务器就是webpack-dev-server,因此咱们对webpack.dev.congfig.js进行更改:
const webpack = require('webpack'); const config = require('./webpack.common.config'); config.devServer = { hot: true, publicPath: '/dist/', historyApiFallback: { index: './index.html' }, } config.plugins.push(new webpack.HotModuleReplacementPlugin()); module.exports = config;
其实就是当服务器找不到路由目录时将页面指向index.html便可。
由于更改了配置,因此咱们须要重启服务器 npm start
进入localhost:8080/demo
页面有显示Hello组件,说明配置成功了。
这里一样因为React-Router版本大更新的问题,因此也要严格控制版本。
安装依赖
npm i -S react-router-redux@4.0.8 @types/react-router-redux@4.0.48
更改index.tsx代码以下:
import * as React from "react"; import * as ReactDOM from "react-dom"; import { Provider } from 'react-redux'; import configureStore from './store/configureStore'; import { Router, browserHistory } from 'react-router'; import routes from './routes'; import { syncHistoryWithStore } from 'react-router-redux'; const store = configureStore(); const history = syncHistoryWithStore(browserHistory, store); ReactDOM.render( <Provider store={store}> <Router history={history} routes={routes} /> </Provider>, document.getElementById('root') as HTMLElement );
而后在src/reducers/index.tsx中添加上routerReducer
import { combineReducers } from 'redux'; import { routerReducer } from 'react-router-redux'; import { enthusiasm } from './demo'; const rootReducer = combineReducers({ demo: enthusiasm, routing: routerReducer }); export default rootReducer;
OK,很是简单。
原本是不打算写一这部分的,毕竟整个基础环境搭下来就只剩loader部分没有写了,而loader配置基本上github对应的库上都有写。
可是我本身装载loader的时候遇到了一些问题,因此这里写出来,避免更多的人踩坑了。
安装依赖
npm i -D css-loader@0.28.7 style-loader@0.19.0
css-loader用来加载css文件,style-loader用来把加载好的文件放入html中的style标签里,因此这两个loader必须配合使用。
编写匹配规则,在webpack.common.config.js中的module.rules中添加以下规则:
{ test: /\.css$/, loader: 'style-loader!css-loader' }
而后咱们建立/src/components/hello.css,并输入如下内容:
.hello{ background:#000; } .greeting{ color:#fff; }
而后在/src/components/Hello.tsx中引入:
import './hello.css';
ok,到目前为止咱们的loader尚未出现问题。
可是你觉得这样就结束了么?那是不可能的,否则我写这部分的目的是什么,手动滑稽。
如今咱们想要用css modules,不知道什么是css modules的请点击CSS Modules 用法教程
因此把webpack.common.config.js中刚刚添加的规则修改为如下内容:
{ test: /\.css$/, loader: "style-loader!css-loader?modules" }
而后更改下/src/components/Hello.tsx对css的引用
import style from "./hello.css";
而后从新编译,报错TS2307: Cannot find module './hello.css'.
什么鬼?找不到css?惊喜不惊喜?
顺手把问题往谷歌一丢,就能找到别人的也碰到了这个问题,下面也有一些解决方案 在这
看下来大概就是有两种解决方案:
一、使用typed-css-modules解决。
二、使用require的方式。
我绝不犹豫的选择了第二种,由于第一种只能解决css的引入问题。那若是我要引入图片文件呢?因此最终仍是要用require。
这部分若是有其余解决方案的话,请大神告诉我一下,不甚感激。
这个报错是typescript报错,咱们只须要在src目录下增长index.d.ts文件便可,内容以下:
declare module '*.scss' { const content: any export default content }
接下来咱们改一下/src/components/Hello.tsx中的引入方式:
const style = require('./hello.css');
若是你是一步步跟着来的话,应该会碰到和我同样的报错:error TS2304: Cannot find name 'require'.
这是由于咱们没有引入@types/node声明文件,因此咱们须要安装一下。
npm i -D @types/node@8.0.34
从新编译一下,终于没有问题了。
接下来继续修改/src/components/Hello.tsx,将class部分修改为css modules的模式
<div className={style.hello}> <div className={style.greeting}> Hello {name + getExclamationMarks(enthusiasmLevel)} </div> <div> <button onClick={onDecrement}>-</button> <button onClick={onIncrement}>+</button> </div> </div>
保存,ok,样式生效。
须要注意的是,若是咱们引入了其余的组件库,好比antd的话,就不能这样直接使用css modules,若是想要使用必须配置以下两条规则:
{ test: /\.css$/, loader: "style-loader!css-loader", include: /node_modules/ },
{ test: /\.css$/, loader: "style-loader!css-loader?modules", exclude: /node_modules/ },
意思应该也都懂了,使用modules的时候须要排除node_modules里引入的那些库。
安装依赖
npm i -D file-loader@1.1.5
在webpack.common.config.js的module.rules中添加规则:
{ test: /\.(png|jpe?g|gif)/, loader: "file-loader" }
而后把在src下建立文件夹img,并放入一张图片,我这里是x.png
在/src/components/Hello.tsx中引入图片,并在JSX中添加一个img标签,一样也须要用require引入
//引入 const imgX = require('../img/x.png'); //JSX部分 <div className={style.hello}> <div className={style.greeting}> Hello {name + getExclamationMarks(enthusiasmLevel)} </div> <div> <button onClick={onDecrement}>-</button> <button onClick={onIncrement}>+</button> </div> <img src={imgX} alt="imgX"/> </div>
保存,进入localhost:8080,然而图片并无出现。
可是若是咱们审查元素的话是能看到有img这个元素的,也就是说引入的位置出了问题。咱们以前说过,webpack-dev-server编译出来的文件是在内存中的,而且目录是/dist/,可是咱们能够很明显的看到咱们img的src值是没有/dist/目录的
因此,咱们须要在webpack.common.config.js的output中再加一条属性 publicPath:'/dist/' ,这个属性的具体含义请看详解Webpack2的那些路径
从新编译,ok,图片显示出来了。
其余的经常使用loader,好比babel,postcss我添加的时候没有遇到什么问题,因此就不贴出来了,若是有人反馈,我再解答吧。
typescript + react-router + webpack 实现按需打包/加载
若是在React-Router和React-Router-Redux的配置中有什么报错,基本上是npm包的版本问题,请删除node_modules并按照我指定的版本从新安装。
总结:安装过程当中确实碰到了各类各样的问题,尤为是Router的包附带的history版本问题,弄了好久。看似很简单的教程,背后有我踩过无数的坑,不过好在仍是完成了。
以后还要继续集成ant-design,以及生产环境的配置,这些都将会在本教程继续更新。
React与webpack | TypeScript Handbook(中文版)