美文网首页
创建一个react+typescript项目#1

创建一个react+typescript项目#1

作者: IamaStupid | 来源:发表于2019-12-18 16:54 被阅读0次

目标:创建一个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;

相关文章

网友评论

      本文标题:创建一个react+typescript项目#1

      本文链接:https://www.haomeiwen.com/subject/xffsnctx.html