转载:https://www.cnblogs.com/baqiphp/p/7647912.html
1 初始化项目
npm init
2 安装依赖
安装webpack和webpack-dev-server
npm install webpack --dev
- 安装webpack和webpack-dev-server时要注意安装版本,版本不兼容时webpack-dev-server指令运行出错:(推荐版本) webpack-dev-server 2.9.1 webpack 3.6.0
- webpack4中webpack和webpack-cli分开!!! 需要webpack、webpack-cli、webpack-dev-server全局和局部都安装
安装React和Types中React的声明文件
npm install react react-dom @types/react @types/react-dom --save
- @types开头的包是typescript的声明文件
安装TypeScript,ts-loader和source-map-loader
npm install typescript ts-loader source-map-loader
- ts-loader 可以让webpack使用typescript的标准配置文件tsconfig.json编译typescript代码
- source-map-loader 生成自己的sourcemaps
3 添加typescript配置文件
当前根目录下创建tsconfig.json文件
{
"compilerOptions": {
"outDir": "./dist/", //输出目录
"sourceMap": true, //生成对应的sourceMap文件
"noImplicitAny": true, //TypeScript 编译器无法推断出类型时,它仍然会生成 JavaScript 文件
"module": "commonjs", //代码规范,也可以选amd
"target": "es5", //转换成es5
"jsx": "react" //TypeScript具有三种JSX模式:preserve,react和react-native
},
"include": [
"./src/**/*" //需要编译的目录。
]
}
创建目录,编写代码
创建目录: components (src)
添加文件: Hero.tsx
import * as React from "react";
export interface ViewProps {
name: string;
age?: number;
}
export interface ViewState {}
export default class Hero extends React.Component<ViewProps,ViewState>{
constructor(props: ViewProps){
super(props);
this.state = {};
}
render(){
const { name, age = 1} = this.props;
return (
<div>
<h6>英雄的信息:</h6>
<p>姓名:{name}</p>
<p>年龄:{age}</p>
</div>
);
}
}
添加文件: index.tsx (src)
import * as React from "react";
import * as ReactDOM from "react-dom";
import Hero from "./components/Hero";
ReactDOM.render(
<Hero name="安其拉" age={5}/>,
document.getElementById("app") as HTMLElement
);
创建目录: public(根目录)
创建文件: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="shortcut icon" href="./logo.jpg">
<title>Model</title>
</head>
<body>
<noscript>Script syntax is not currently supported</noscript>
<div id="app"></div>
<script src="../dist/bundle.js"></script>
</body>
</html>
编写webpack配置文件
创建文件: webpack.common.config.js (根目录)
- 配置开发、生成的通用环境
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist",
publicPath: "./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 --config webpack.common.config.js
- 打开index.html查看页面
-
! 如果webpack -v 出错,需安装webpack-cli
编写webpack开发环境配置文件
安装webpacl-dev-server
npm install webpack-dev-server --dev
- webpacl-dev-server提供的最基本也是最好用的热更新功能
添加文件: webpack.dev.config.js
const webpack = require('webpack');
//引入公共配置
const config = require('./webpack.common.config');
//配置webpack-dev-server
config.devServer = {
hot: true, //开启热更新
publicPath: '/dist/' //webpack-dev-server编译后资源存放地址
}
config.plugins.push(new webpack.HotModuleReplacementPlugin());
module.exports = config;
运行命令:
webpack-dev-server --config webpack.dev.config.js
-
打开网页,进入localhots:8080就可以看到我们的页面了。
-
打开浏览器的开发者工具,在console部分能看到以下两句提示就说明热更新启动成功了。
[HMR] Waiting for update signal from WDS... [WDS] Hot Module Replacement enabled.
-
在package.json的scripts下添加 "start": "webpack-dev-server --config webpack.dev.config.js"
-
输入npm start 启动服务。
添加简单的redux
安装依赖
npm install redux react-redux @types/react-redux --save
创建目录: types (src)
创建文件: index.tsx (存放store的接口声明)
export interface StoreState {
languageName: string;
enthusiasmLevel?: number;
}
创建目录: constants (src)
创建文件: index.tsx (定义action和reducer使用的常量)
export const INCREMENT_ENTHUSIASM = "INCREMENT_ENTHUSIASM";
export type INCREMENT_ENTHUSIASM = typeof INCREMENT_EMTHUSIASM;
export const DECREMENT_ENTHUSIASM = "DECREMENT_ENTHUSIASME";
export type DECREMENT_ENTHUSIAM = typeof DECREMENT_ENTHUSIASM;
创建目录: actions (src)
创建文件: index.tsx (存放action)
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
}
}
创建目录: reducers (src)
创建文件: index.tsx (存放reducer)
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:
{ ...state, enthusiasmLevel: Math.max(1,state.enthusiasmLevel - 1)};
default:
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("error");
}
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("!");
}
创建目录: containers (src)
创建文件: Hello.tsx (Hello组件连接到redux的store中)
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);
创建目录: store (src)
创建文件: initState.tsx (定义store的初始值)
export default {
enthusiasmLevel: 1,
languageName: "TypeScript"
}
创建文件: configureStore.tsx (创建store)
import { createStore } from "redux";
import { enthusiasm } from "../reducers/index";
import { StoreState } from "./initState";
export default function() {
const store = createStore<StoreState>(enthusiasm,initState);
export store;
}
修改文件: index.tsx (src)
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组件
》》》待完善
添加React-Router
添加React-Router-Redux
添加开发必备配置
css-loader
安装依赖
npm install css-loader style-loader --dev
- css-loader 用来加载css文件
- style-loader 把加载好的文件放入html中
编写匹配规则:
{ test: /.css$/, loader: "style-loader!css-loader?modules" }
- 没有引用组件库
{ test: /.css$/,loader: "style-loader!css-loader", include: /node_modules/ }
{ test: /.css$/,loader: "style-loader!css-loader?modules", exclude: /node_modules/ }
- 引用了组件库
file-loader
安装依赖
npm install file-loader --dev
编写匹配规则:
{ test: /.(png|jpe?g|gif)/, loader: "file-loader" }