目标:创建一个react项目,并使用typescript编写代码
1.创建文件夹react-ts01
2.打开cmd界面,到react-ts01目录下去,执行命令:
npm init
生成package.json文件
3.然后需要安装打包器webpack
npm install --save-dev webpack webpack-cli
package.json文件里面多了webpack 的内容:
"devDependencies": {
"webpack": "^4.41.3",
"webpack-cli": "^3.3.10"
}
创建新的 React 应用:https://react.docschina.org/docs/create-a-new-react-app.html#create-react-app
4. 需要安装语法转换器babel
// babel
npm install --save-dev @babel/core @babel/cli @babel/preset-env
// react
npm install --save-dev babel-loader @babel/preset-react
// typescript preset翻译:预设置
npm install --save-dev @babel/preset-typescript
babel使用指南:https://www.babeljs.cn/docs/usage
5. 安装react 和 typescript
npm install --save react react-dom react-router-dom @types/react @types/react-dom @types/react-router-dom
npm install --save-dev typescript awesome-typescript-loader source-map-loader
@types开头的两个react包都是typeScript的声明文件,你可以进入node_modules / @types / XX / index.d.ts 进行查看
package.json针对react增加了如下配置:
"dependencies": {
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2"
}
这些typescript相关的依赖会让TypeScript和webpack在一起良好地工作。 awesome-typescript-loader可以让Webpack使用TypeScript的标准配置文件 tsconfig.json编译TypeScript代码。 source-map-loader使用TypeScript输出的sourcemap文件来告诉webpack何时生成 自己的sourcemaps。 这就允许你在调试最终生成的文件时就好像在调试TypeScript源码一样。
TypeScript & React & Webpack:https://www.tslang.cn/docs/handbook/react-&-webpack.html
6. 开始webpack配置
1)package.json
删除package.json入口文件配置main:"index.js",添加 "private": true,修改script:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js"
},
1.1) 增加一个文件tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": [
"./src/**/*"
]
}
tsconfig.json更多相关信息:https://www.tslang.cn/docs/handbook/tsconfig-json.html
2)
2.1) 创建config文件夹,再创建index.js文件
config/index.js
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: { // cross origin setting
'/': {
target: 'http://121.12.87.143:80',
secure: false,
changeOrigin: true,
pathRewrite: {
'^/': '/'
}
}
},
// Various Dev Server settings
host: 'localhost',
port: 8899,
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', // 服务器发布 需要用 './'
/**
* Source Maps
*/
productionSourceMap: false,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
}
}
2.2) 创建build文件夹,用来存放打包构建的代码,并在文件夹中创建webpack.dev.js / webpack.prod.js / webpack.common.js
// dist中生成index.html的就是它的功能
np m install --save-dev html-webpack-plugin
// 在本地临时构建一个server
npm install --save-dev webpack-dev-server
// 提供了一个合并对象的方法
npm install --save-dev webpack-merge
// set NODE_ENV=production貌似在mac上会有问题
npm install --save-dev cross-env
webpack.common.js
'use strict'
// nodejs path模块
const path = require('path')
let NodeEnv = process.env.NODE_ENV
function resolve (dir) {
// nodejs中__dirname 总是指向被执行 js 文件的绝对路径 => /build/
return path.join(__dirname, '..', dir)
}
let config = require(resolve('config/') + 'index.js')
console.log('webpack.common.js NODE_ENV:',process.env.NODE_ENV);
module.exports = {
// context: path.resolve(__dirname, '../'),
entry: {
// output的name变量值就是main
main: './src/main.tsx'
// main: './src/index.js'
// main: ['babel-polyfill', './src/main.js']
},
output: {
path: resolve('dist'),
filename: '[name].js',
publicPath: NodeEnv === 'production' || NodeEnv === 'git'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.ts', '.vue', '.jsx', '.tsx', '.json', '.css', '.scss', '.less'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'@utils': resolve('src/utils'),
'@views': resolve('src/views'),
'@com': resolve('src/views/components')
}
},
module: {
rules: [
// ...(config.dev.useEslint ? [createLintingRule()] : []),
// {
// test: /\.vue$/,
// loader: 'vue-loader',
// options: vueLoaderConfig
// },
{
test: /\.(js|jsx)$/,
loader: 'babel-loader?cacheDirectory=true', // 使用cache提升编译速度
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
// options: {
// presets: ["env"],
// plugins: ["transform-runtime"]// 避免重复引入
// }
},
// {
// test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
// loader: 'url-loader',
// options: {
// limit: 1999999,
// name: utils.assetsPath('img/[name].[hash:7].[ext]')
// }
// },
// {
// test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
// loader: 'url-loader',
// options: {
// limit: 10000,
// name: utils.assetsPath('media/[name].[hash:7].[ext]')
// }
// },
// {
// test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
// loader: 'url-loader',
// options: {
// limit: 10000,
// name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
// }
// }
// {
// // test: /\.(less|sass|scss)\??.*$/,
// // loader: 'style-loader!css-loader!sass-loader!less-loader'
// test: /\.(less|sass|scss)(\?.*)?$/,
// loader: 'style!css!sass!less'
// }
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.(tsx|ts)?$/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
webpack.dev.js
'use strict'
// nodejs path模块
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
let config = require(path.join(__dirname, '..', 'config/') + 'index.js')
module.exports = merge(common, {
mode: 'development',
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
hotOnly: true, // 即便HMP的功能没有生效,浏览器也不能自动刷新
// contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: config.dev.host,
port: config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
// quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll
}
},
plugins: [
new HtmlWebPackPlugin({
favicon: './static/favicon.png',
template: "./src/index.html",
filename: 'index.html'
})
]
});
webpack.prod.js
'use strict'
const HtmlWebPackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
plugins: [
new HtmlWebPackPlugin({
favicon: './static/favicon.png',
template: "./src/index.html",
filename: 'index.html'
})
]
});
7. 写个简单的测试代码,新建一个文件夹src,再创建main.tsx和App.tsx文件,代码如下:
main.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App compiler="TypeScript" framework="React"/>,
document.getElementById('app')
);
App.tsx
import * as React from 'react'
// import {Route, HashRouter} from 'react-router-dom'
export interface HelloProps {
compiler: string;
framework: string;
}
class App extends React.Component<HelloProps, object> {
render(){
return(
<div>
<h1>react and typescript</h1>
<div>props: {this.props.compiler} and {this.props.framework}</div>
</div>
)
}
}
export default App;
网友评论