美文网首页
创建一个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