René's URL Explorer Experiment


Title: 一个react项目 · Issue #8 · wython/wython.github.io · GitHub

Open Graph Title: 一个react项目 · Issue #8 · wython/wython.github.io

X Title: 一个react项目 · Issue #8 · wython/wython.github.io

Description: 一个react项目 这是一篇关于搭建react项目的基础文章。我决定一个react项目包含前端工程化部分和react技术栈部分。对于前端工程化,采用webpack做工程化是主流的方式。react的技术栈会用到redux和react-router。 webpack的职责 webpack的功能是模块化打包工具。 使用webpack 4 所以,直接使用babel是可以编译react的jsx的,但是使用webpack做工程化很重要,很多开发工作都需要用到webpack,所以可以...

Open Graph Description: 一个react项目 这是一篇关于搭建react项目的基础文章。我决定一个react项目包含前端工程化部分和react技术栈部分。对于前端工程化,采用webpack做工程化是主流的方式。react的技术栈会用到redux和react-router。 webpack的职责 webpack的功能是模块化打包工具。 使用webpack 4 所以,直接使用babel是可以编译react的jsx的,但是...

X Description: 一个react项目 这是一篇关于搭建react项目的基础文章。我决定一个react项目包含前端工程化部分和react技术栈部分。对于前端工程化,采用webpack做工程化是主流的方式。react的技术栈会用到redux和react-router。 webpack的职责 webpack的功能是模块化打包工具。 使用webpack 4 所以,直接使用babel是可以编译react的jsx的,但是...

Opengraph URL: https://github.com/wython/wython.github.io/issues/8

X: @github

direct link

Domain: patch-diff.githubusercontent.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"一个react项目","articleBody":"## 一个react项目\r\n\r\n这是一篇关于搭建react项目的基础文章。我决定一个react项目包含前端工程化部分和react技术栈部分。对于前端工程化,采用webpack做工程化是主流的方式。react的技术栈会用到redux和react-router。\r\n\r\n### webpack的职责\r\nwebpack的功能是模块化打包工具。\r\n\r\n### 使用webpack 4\r\n所以,直接使用babel是可以编译react的jsx的,但是使用webpack做工程化很重要,很多开发工作都需要用到webpack,所以可以先了解基础的webpack功能。先创建文件夹 an-react-project\r\n``` shell\r\nnpm init\r\n```\r\n``` shell\r\nnpm install --save-dev webpack webpack-cli webpack-dev-server\r\n```\r\n初始化npm, 安装webpack。然后弄一个简单的目录结构了解下webpack的基本功能。这样安装默认就是最新webpack4\r\n\r\n```\r\n|-- dist\r\n    |-- index.html\r\n|-- src\r\n    |-- index.js\r\n    |-- moduleA.js\r\n    |-- moduleB.js\r\n|-- package.json\r\n|-- webpack.config.js\r\n```\r\n\r\nwebpack.config.js:\r\n\r\n```javascript\r\nconst path = require('path');\r\nmodule.exports = {\r\n  entry: './src/index.js',\r\n  output: {\r\n    filename: 'bundle.js',\r\n    path: path.resolve(__dirname, 'dist')\r\n  }\r\n}\r\n```\r\nsrc/index.js:\r\n```javascript\r\n// index.js\r\nimport moduleA from './moduleA';\r\nimport moduleB from './moduleB';\r\n\r\n\r\nfunction createComponent() {\r\n  var element = document.createElement('div');\r\n\r\n  var btn = document.createElement('button');\r\n  var btnTwo = document.createElement('button');\r\n  element.innerHTML = 'Hello World';\r\n\r\n  btn.innerHTML = 'print btn';\r\n  element.appendChild(btn);\r\n  element.appendChild(btnTwo);\r\n  btn.onclick = moduleA\r\n  btnTwo.onclick = moduleB\r\n  return element;\r\n}\r\n\r\ndocument.body.appendChild(createComponent())\r\n\r\n```\r\n\r\nsrc/moduleA.js:\r\n```javascript\r\nexport default function printHello() {\r\n  console.log('Ok')\r\n  console.log('From printHello')\r\n}\r\n```\r\n\r\nsrc/moduleB.js:\r\n```javascript\r\nexport default function printHelloTwo() {\r\n  console.log('Yes')\r\n  console.log('From moduleB')\r\n}\r\n```\r\n\r\npackage.js定义命令:\r\n```\r\n...\r\n\"scripts\": {\r\n    \"start\": \"webpack --config webpack.config.js\",\r\n},\r\n...\r\n```\r\n执行npm run start 或者 yarn start命令可以看到dist中已经打包出了bundle.js。直接访问index.html可以看到静态页面。目前的配置和react没有任何关系,仅仅只是webpack的基本功能。并且定义了一个入口和输出路径。具体的可以看webpack文档指南。有更详细的配置细节。\r\n\r\nsource map:\r\nwebpack打包后的代码,如果需要追踪错误位置。就比较难,source map功能可以定义webpack配置的devtool来追踪源代码。\r\n\r\n```javascript\r\nconst path = require('path');\r\nmodule.exports = {\r\n  entry: './src/index.js',\r\n  output: {\r\n    filename: 'bundle.js',\r\n    path: path.resolve(__dirname, 'dist')\r\n  },\r\n  devtool: 'inline-source-map'\r\n}\r\n```\r\n不过越原始的追踪带来性能会更差。可以看下文档支持的配置: \r\n[webpack devtool](https://webpack.docschina.org/configuration/devtool)\r\n\r\nwebpack-dev-server:\r\n\r\n上面已经安装了webpack-dev-server。开发环境通过devServer配置开启。可以不需要每次修改都重新编译。实时监听编译。webpack有三种方式支持监听,watch配置,webpack-dev-middleware配置。webpack-dev-server就是基于webpack-dev-middleware实现的,同时具有更多功能配置。一般都会用webpack-dev-server,但是如果希望自己编写server逻辑,可以考虑结合node后端和middleware自己实现。\r\n```javascript\r\nconst path = require('path');\r\nmodule.exports = {\r\n  mode: 'development',\r\n  entry: './src/index.js',\r\n  output: {\r\n    filename: 'bundle.js',\r\n    path: path.resolve(__dirname, 'dist')\r\n  },\r\n  devtool: 'inline-source-map',\r\n  devServer: {\r\n    contentBase: './dist'\r\n  }\r\n}\r\n```\r\n这个时候修改package.json启动命令用webpack-dev-server启动可以看到浏览器会用node服务方式访问页面。\r\n\r\nwebpack插件配置html-webpack-plugin和clean-webpack-plugin:\r\n\r\n当然,因为index.html是我们自己编写的,一般会通过html-webpack-plugin维护html,这个插件非常有必要,因为对于后面的项目部署,动态生成hash文件名的方式引入html中,如果人为维护基本是一件很繁琐的事情,插件可以根据配置自己引入script脚本。\r\n\r\nclean-webpack-plugin用于每次启动或者编译工程时候保持文件夹是干净的。它会清理文件夹下的命令。\r\n\r\nwebpack插件的配置通过plugin数组配置。\r\n```javascript\r\nconst path = require('path');\r\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\r\nconst { CleanWebpackPlugin } = require('clean-webpack-plugin');\r\n\r\nmodule.exports = {\r\n  mode: 'development',\r\n  entry: './src/index.js',\r\n  output: {\r\n    filename: 'bundle.js',\r\n    path: path.resolve(__dirname, 'dist')\r\n  },\r\n  devtool: 'inline-source-map',\r\n  devServer: {\r\n    contentBase: './dist'\r\n  },\r\n  plugins: [\r\n    new CleanWebpackPlugin({ default: [ 'dist' ] }),\r\n    new HtmlWebpackPlugin({\r\n      title: 'hello world'\r\n    })\r\n  ]\r\n}\r\n```\r\n再次启动项目时候,这时候dist文件夹应该已经没有文件。因为开发环境下,dev-server是将编译文件载入内存中。这样可以提高更新效率,因为对计算机而已,读取硬盘比读内存要耗时的多。\r\n\r\n### Babel的职责\r\nBabel的工作是转换js语法,比如平时用到的jsx,浏览器不支持的es6语法,ts语法。都是babel做编译的工作。如果不了解每一个模块的职责,很容易混淆webpack,babel的关系。\r\n\r\n### 使用babel\r\n配置babel有两种方式,一种是通过创建babel.config.js配置文件,另一种是.babelrc。前者是js形式,如果希望做一些脚本工作通过配置去配置是不错的。不过我们需要借助webpack loader方式去做,所以不需要在两个文件中做配置。\r\n\r\nbabel是通过plugins和presets的两种方式去扩展需要的语法。\r\n\r\n```json\r\n{\r\n  \"presets\": [],\r\n  \"plugins\": []\r\n}\r\n```\r\npresets是一组plugins的集合。一般来说用已有的preset足够满足要求。安装babel和@babel/core。和react的@babel/preset-react。同时安装react和react-dom框架和\r\n\r\n```shell\r\nyarn add babel @babel/core @babel/preset-react --dev\r\nyarn add react react-dom --save\r\n```\r\n\r\n重新编辑src/index.js:\r\n\r\n```javascript\r\nimport React from 'react';\r\nimport ReactDOM from 'react-dom';\r\n\r\n\r\nReactDOM.render(\u003ch1\u003ehello world!\u003c/h1\u003e, document.getElementById('app'))\r\n```\r\n\r\n#### 整理webpack配置文件\r\n现在只有一个webpack.config.js,不过一般项目会分开发环境和生产环境,不同的环境webpack的职责也不同。所以可以提前建好不同的配置文件,通过webpack-merge合并配置。\r\n```\r\nyarn add webpack-merge --dev\r\n```\r\n我自己的话,创建文件夹build,把配置文件放进去。文件目录如下:\r\n\r\n```markdown\r\n  |-- package.json\r\n  |-- yarn.lock\r\n  |-- build\r\n  |   |-- webpack.base.config.js\r\n  |   |-- webpack.dev.config.js\r\n  |   |-- webpack.pro.config.js\r\n  |   |-- webpack.vendor.config.js\r\n  |-- dist\r\n  |-- src\r\n      |-- index.js\r\n      |-- asset\r\n          |-- index.html\r\n```\r\n\r\nwebpack.base.config.js:\r\n\r\n```javascript\r\nconst path = require('path');\r\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\r\nconst { CleanWebpackPlugin } = require('clean-webpack-plugin');\r\nconst webpack = require('webpack');\r\n\r\nmodule.exports = {\r\n  entry: './src/index.js',\r\n  output: {\r\n    filename: 'bundle.js',\r\n    path: path.resolve(__dirname, 'dist')\r\n  },\r\n  plugins: [\r\n    new CleanWebpackPlugin({ default: [ 'dist' ] }),\r\n    new HtmlWebpackPlugin({\r\n      template: './src/asset/index.html'\r\n    })\r\n  ]\r\n}\r\n```\r\n\r\nwebpack.dev.config.js:\r\n```javascript\r\nconst webpackMerge = require('webpack-merge');\r\nconst baseConfig = require('../build/webpack.base.config');\r\nconst path = require('path');\r\nconst srcPath = path.join(__dirname, '../src');\r\nconst devConfig = {\r\n  mode: 'development',\r\n  devtool: 'inline-source-map',\r\n  devServer: {\r\n    contentBase: './dist'\r\n  },\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: /\\.(js|jsx)$/,\r\n        include: srcPath,\r\n        use: [\r\n          {\r\n            loader: 'babel-loader',\r\n            options: {\r\n              presets: ['@babel/preset-react'],\r\n            }\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  }\r\n}\r\n\r\nmodule.exports = webpackMerge(baseConfig, devConfig);\r\n```\r\n\r\n修改package.json命令:\r\n```json\r\n...\r\n\"scripts\": {\r\n  \"start\": \"webpack-dev-server --open --config ./build/webpack.dev.config.js\"\r\n}\r\n...\r\n```\r\n此时,通过访问server对应页面可以看到结果,说明jsx代码已经成功转义。基础配置完成。\r\n\r\n### webpack的一些优化\r\n以上配置相对基础,优化是一个持续过程,但是如果一开始能做好的优化,对后续会更有帮助。对webpack的优化可以分开发环境下的优化和生产环境下的优化\r\n\r\n### 开发环境\r\n开发环境下,需要提高实时编译时间,做到最好的开发体验。\r\n\r\n#### 1. dllPlugin提取公共库\r\n先介绍下dllPlugin,这个组件用用于单独抽离部分公共组件库。平时开发过程中,有些库,例如上面涉及到的react,react-dom这些库,一般一个项目定型之后,不会频繁修改库的内容和版本。所以上面的配置每一次启动项目都会编译一次公共库。实际上是没有必要的,因为这个过程是重复的,公共库并没有发生变化。最好的思路是将他们提取出来,之后每一次构建就不会再去编译这些代码。\r\n\r\n要使用dllPlugin,只需要在webpack.vendor.config.js中配置插件和需要打包的包。然后通过DllReferencePlugin引用依赖关系即可。\r\n\r\n在webpack.vendor.config.js中:\r\n```javascript\r\nconst webpack = require('webpack');\r\nconst path = require('path');\r\nmodule.exports = {\r\n  mode: 'development',\r\n  entry: {\r\n    vendor: ['react', 'react-dom']\r\n  },\r\n  output: {\r\n    filename: '[name].dll.js',\r\n    path: path.join(__dirname, '..', 'dist'),\r\n    library: 'vendor_lib_[hash]'\r\n  },\r\n  plugins: [\r\n    new webpack.DllPlugin({\r\n      context: __dirname, // 上下文\r\n      path: path.join(__dirname, '..', 'dist', 'vendor-manifest.json'),\r\n      name: 'vendor_lib_[hash]' // 与out的libirary库名保持一致\r\n    })\r\n  ]\r\n}\r\n```\r\n\r\n插件的path定义的是依赖文件的保存路径,webpack的另一个插件需要这个依赖文件来保证能访问对应库。\r\n\r\nwebpack.dev.config.js:\r\n```javascript\r\nconst webpackMerge = require('webpack-merge');\r\nconst baseConfig = require('../build/webpack.base.config');\r\nconst webpack = require('webpack');\r\nconst path = require('path');\r\nconst srcPath = path.join(__dirname, '../src');\r\nconst devConfig = {\r\n  mode: 'development',\r\n  devtool: 'inline-source-map',\r\n  devServer: {\r\n    contentBase: './dist'\r\n  },\r\n  plugins: [\r\n    new webpack.DllReferencePlugin({\r\n      context: __dirname,\r\n      manifest: require('../dist/vendor-manifest.json')\r\n    })\r\n  ],\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: /\\.(js|jsx)$/,\r\n        include: srcPath,\r\n        use: [\r\n          {\r\n            loader: 'babel-loader',\r\n            options: {\r\n              presets: ['@babel/preset-react'],\r\n            }\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  }\r\n}\r\n\r\nmodule.exports = webpackMerge(baseConfig, devConfig);\r\n```\r\n\r\n然后通过DllReferencePlugin定义即可,具体参数可以看官方文档的配置项目。\r\n\r\n\r\n#### 2. 使用热替换(HRM)\r\n热替换功能用于提高开发效率,它的功能是可以无刷新页面的情况下重新载入新模块。这个不能和dev-server的实时监控搞混。现在虽然代码修改,页面实时刷新,但是热替换可以做到不刷新页面就能显示内容的更改。\r\n\r\n想象这样一个场景,平时在开发类似modal弹窗这样的组件时候,如果你修改了modal页面刷新,modal就不见了,需要重新弹窗。如果用了热替换,实时修改将不会刷新页面,弹窗不会消失,这对开发效率是有一定提高的。\r\n\r\n在src文件夹下加上两个文件:\r\n```\r\n|-- src\r\n    |-- index.js\r\n    + |-- app.js\r\n    + |-- header.js\r\n```\r\n\r\napp.js:\r\n```javascript\r\nimport React, { Component, Fragment } from 'react';\r\nimport Header from './header';\r\n\r\nexport default class App extends Component {\r\n  render() {\r\n    return (\r\n      \u003cFragment\u003e\r\n        \u003cHeader /\u003e\r\n        \u003ch1\u003ehello world!\u003c/h1\u003e\r\n      \u003c/Fragment\u003e\r\n      \r\n    )\r\n  }\r\n}\r\n```\r\n\r\nheader.js:\r\n```javascript\r\nimport React, {  Component } from 'react';\r\n\r\nexport default class Header extends Component {\r\n  render() {\r\n    return (\r\n      \u003cheader\u003e头部\u003c/header\u003e\r\n    )\r\n  }\r\n}\r\n```\r\n\r\nindex.js:\r\n```javascript\r\nimport React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport App from './app';\r\n\r\nReactDOM.render(\u003cApp /\u003e, document.getElementById('app'))\r\n```\r\n\r\n现在如果修改header.js组件页面会刷新一下。\r\n\r\n要开启webpack热替换,需要以下步骤:\r\n\r\n1. 使用webpack.HotModuleReplacementPlugin,在配置中把derServer hot设置为ture。\r\n\r\n即:\r\n```javascript\r\n...\r\ndevServer: {\r\n  contentBase: './dist',\r\n  hot: true\r\n},\r\nplugins: [\r\n  new webpack.HotModuleReplacementPlugin()\r\n  ...\r\n],\r\n...\r\n```\r\n\r\n2. 对于基础项目(原始js项目),需要在入口js文件中监听引用的模块\r\n例子:\r\n```javascript\r\nif (module.hot) {\r\n  module.hot.accept('./app.js', function(){\r\n    // app.js变化之后需要做的操作,这根据具体场景配置\r\n  })\r\n}\r\n```\r\n\r\n#### react项目的热更新配置\r\n\r\n对于react项目,需要用到第三方的插件 react-hot-loader。基于webpack的HotModuleReplacementPlugin,所以上面webpack的配置应该保留。但是入口文件则无需你处理module.hot.accept里面的逻辑。\r\n\r\n1. 安装:\r\n```\r\nyarn add react-hot-loader --dev\r\n```\r\n\r\n2. 入口组件,比如上面react例子中的app.js\r\n\r\napp.js:\r\n```javascript\r\nimport React, { Component, Fragment } from 'react';\r\nimport Header from './header';\r\n\r\nimport { hot } from 'react-hot-loader/root';\r\n\r\nconst App = class App extends Component {\r\n  render() {\r\n    return (\r\n      \u003cFragment\u003e\r\n        \u003cHeader /\u003e\r\n        \u003ch1\u003ehello world!\u003c/h1\u003e\r\n      \u003c/Fragment\u003e\r\n      \r\n    )\r\n  }\r\n}\r\n\r\nexport default hot(App);\r\n```\r\n\r\n3. babel配置中添加react-hot-loader\r\n\r\n我是写在options里面,如果使用.babelrc配置,一样道理。\r\n```\r\n{\r\n  presets: ['@babel/preset-react'],\r\n  plugins: ['react-hot-loader/babel']\r\n}\r\n```\r\n\r\n此时热更新应该生效,修改header文本,可以看到页面无刷新修改了最新内容。不过此时启动项目,react-hot-loader会有个wraning,大体意思是对于react 16.4之后的版本,应该使用扩展@hot-loader/react-dom,否则无法在部分特性里面使用热更新,其实指的是react hook的语法。\r\n\r\n只需要按照扩展,然后定义别名使得原始的react-dom包从@hot-loader/react-dom中获取就行了。\r\n\r\n```\r\nyarn add @hot-loader/react-dom\r\n```\r\nwebpack.dev.config.js完整配置如下:\r\n```javascript\r\nconst webpackMerge = require('webpack-merge');\r\nconst baseConfig = require('../build/webpack.base.config');\r\nconst webpack = require('webpack');\r\n\r\nconst path = require('path');\r\nconst srcPath = path.join(__dirname, '../src');\r\n\r\nconst devConfig = {\r\n  mode: 'development',\r\n  devtool: 'inline-source-map',\r\n  plugins: [\r\n    new webpack.DllReferencePlugin({\r\n      context: __dirname,\r\n      manifest: require('../dist/vendor-manifest.json')\r\n    }),\r\n    new webpack.HotModuleReplacementPlugin()\r\n  ],\r\n  devServer: {\r\n    contentBase: './dist',\r\n    hot: true\r\n  },\r\n  resolve: {\r\n    alias: {\r\n      'react-dom': '@hot-loader/react-dom'\r\n    }\r\n  },\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: /\\.(js|jsx)$/,\r\n        include: srcPath,\r\n        use: [\r\n          {\r\n            loader: 'babel-loader',\r\n            options: {\r\n              presets: ['@babel/preset-react'],\r\n              plugins: ['react-hot-loader/babel']\r\n            }\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  }\r\n}\r\n\r\nmodule.exports = webpackMerge(baseConfig, devConfig);\r\n\r\n```\r\n\r\n\r\n#### 减少查找范围\r\n其实我上面配置对插件的include已经设置了,实际上就是js文件只查找src文件夹下的文件。\r\n\r\n#### 针对性的loader实行优化\r\n这个是具有灵活性的优化,比如以上的babel-loader。来看看官方文档对babel-loader的自我评价。\r\n\r\n![babel-loader](https://user-images.githubusercontent.com/15258919/68285456-4634bd80-00ba-11ea-95d6-d8fd0e21c625.png)\r\n\r\nbabel-loader可以通过cacheDirectory实现缓存。所以,用上它。修改配置:\r\n```javascript\r\n...\r\nrules: [\r\n  {\r\n    test: /\\.(js|jsx)$/,\r\n    include: srcPath,\r\n    use: [\r\n      {\r\n        loader: 'babel-loader',\r\n        options: {\r\n          presets: ['@babel/preset-react'],\r\n          plugins: ['react-hot-loader/babel'],\r\n          cacheDirectory: '../runtime_cache/'\r\n        }\r\n      }\r\n    ]\r\n  }\r\n]\r\n...\r\n```\r\n\r\n#### 有名气的happypack\r\n作用:webpack本身是单线程处理模块的,happyPack可以让部分loader在多线程下去处理文件。\r\n\r\n那平时对一些比较耗时的loader可以使用happyPack做性能优化。比如上面的babel,它自己都说自己很慢。\r\n\r\n使用happypack,需要修改loader和插件,我们只修改部分费时的loader就行了,loader里面:\r\n\r\nwebpack.dev.config.js\r\n```javascript\r\nconst webpackMerge = require('webpack-merge');\r\nconst baseConfig = require('../build/webpack.base.config');\r\nconst webpack = require('webpack');\r\nconst HappyPack = require('happypack');\r\n\r\nconst path = require('path');\r\nconst srcPath = path.join(__dirname, '../src');\r\n\r\nconst devConfig = {\r\n  mode: 'development',\r\n  devtool: 'inline-source-map',\r\n  plugins: [\r\n    new webpack.DllReferencePlugin({\r\n      context: __dirname,\r\n      manifest: require('../dist/vendor-manifest.json')\r\n    }),\r\n    new webpack.HotModuleReplacementPlugin(),\r\n    new HappyPack({ \r\n      id: 'js',\r\n      loaders: [ \r\n        {\r\n          loader: 'babel-loader',\r\n          options: {\r\n            presets: ['@babel/preset-react'],\r\n            plugins: ['react-hot-loader/babel'],\r\n            cacheDirectory: '../runtime_cache/'\r\n          }\r\n        } \r\n      ]\r\n    })\r\n  ],\r\n  devServer: {\r\n    contentBase: './dist',\r\n    hot: true\r\n  },\r\n  resolve: {\r\n    alias: {\r\n      'react-dom': '@hot-loader/react-dom'\r\n    }\r\n  },\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: /\\.(js|jsx)$/,\r\n        include: srcPath,\r\n        use: 'happypack/loader?id=js'\r\n      }\r\n    ]\r\n  }\r\n}\r\n\r\nmodule.exports = webpackMerge(baseConfig, devConfig);\r\n```\r\n\r\n### 整理目录接入ts\r\n\r\n\r\n对于一个开发团队来说,ts可能不是必要的。首先,要权衡typescript是否适合在一个项目中使用。ts是js的一个超集。它提供了一些类型校验的东西,当然也会牺牲一些开发效率上的东西。但是从长远来说,对开发效率更多是利大于弊,它可以避免一些人为错误,数据流转中松散类型带来对不确定问题。我觉得一个项目适不适合用ts,主要还是看这个项目是不是长期迭代,体量的大小。对于一些用完即走的活动页,可能ts反而是一个累赘。另外,本身折腾ts也是一个繁琐的事情,包括接口,类型的定义,有时候比正常js会多一些工作量。如果不按ts规范走,那其写法也和js没有区别,还不如不用。\r\n\r\nwebpack中使用ts思路很简单。因为本身ts只需要一个tsconfig.json的文件。而前端打包ts主要还是ts-loader和babel-loader两种。这里我两种都尝试了,最后babel-loader对热加载更友好。因为热加载插件中官方文档对ts对说法是这样的。\r\n\r\n![react-hot-loader](https://user-images.githubusercontent.com/15258919/78096640-b7c82c00-740c-11ea-86be-30415c458422.png)\r\n大体意思是,对于react-hot-loader 4的版本来说,你必须用babel转换才行,这对于一些其实不需要使用babel的用户来说不太友好。幸运的是,babel的配置很简单,而且集成的也很好。所以,让你大胆的用babel-loader代替ts-loader去做这件事。\r\n\r\n安装: \r\n@babel/preset-env, @babel/preset-typescript,@babel/plugin-proposal-decorators,@babel/plugin-proposal-class-properties 四个preset集合,env集成了很多常用写法,typescript就是用babel转ts的集合。后面两个是在ts中使用装饰器语法所用。\r\n安装:\r\ncore-js regenerator-runtime babel7.4之后把polyfill拆分成两个模块。如果需要做babel升级迁移,要考虑polyfill问题。\r\n\r\nbase.js:\r\n```\r\nextensions: ['.ts', '.tsx', '.js', '.json'],  // 默认是['.js', '.json'], ts需要扩展支持的后缀名\r\n```\r\n配置功能是不需要写后缀即可导入模块\r\n\r\ntest正则修改为:test: /\\.(j|t)sx?$/,\r\nloader中添加babel上面装对preset,和插件\r\n```\r\nnew HappyPack({ \r\n      id: 'js',\r\n      loaders: [ \r\n        {\r\n          loader: 'babel-loader',\r\n          type: 'javascript/auto',\r\n          options: {\r\n            presets: [\r\n              +++ \"@babel/preset-env\",\r\n              +++ \"@babel/preset-typescript\",\r\n              '@babel/preset-react'\r\n            ],\r\n            plugins: [\r\n              +++ ['@babel/plugin-proposal-decorators', { legacy: true }],\r\n              +++ ['@babel/plugin-proposal-class-properties', { loose: true }],\r\n              'react-hot-loader/babel'\r\n            ],\r\n            cacheDirectory: './runtime_cache/'\r\n          }\r\n        } \r\n      ]\r\n    })\r\n```\r\n然后src都.js文件都改成ts写法。基本ts的引入就完成了。\r\n\r\n### 引入less和文件模块化\r\nless需要less-loader转换,css需要css-loader转换,style-loader将样式提取到style标签中,生产环境则用mini-css-extract-plugin将样式提取到单独文件中。\r\n\r\nless: less-loader() css-loader(解释(interpret) @import 和 url()) extract-loader to-string-loader \r\nstyle-loader(inject \u003cstyle\u003e) extractTextPlugin\r\n\r\n### 项目可能用到的技术\r\n\r\n上面基本罗列了开发前需要做的工作,webpack部分开发配置,但在整体还是和简陋的。不过到这里,就可以开始思考一个项目可能会用到的一些东西。比如单页router,状态管理redux等,由于用ts语法,也可以试试比较友好的mobx。但这些其实不是重点,重点是保证项目但稳定,开发效率,以及未来可能但性能,扩展。\r\n\r\n所以,先装上react-router,antd,mobx,react-mobx以及相关的@types声明。\r\n\r\n现在可以假设一个项目,后台项目包括登陆,注册,以及登陆进去之后内容页面,内容页面包含不同路由对应的路由模块。","author":{"url":"https://github.com/wython","@type":"Person","name":"wython"},"datePublished":"2019-11-05T11:02:31.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/8/wython.github.io/issues/8"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:5cc45517-579a-6c47-09df-787ff5a57378
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-idECE2:285CE0:651336:81436F:69757F2A
html-safe-nonce3769e99510c25a2042b27f9b44d63257bc2bfeb232b0e9d2eee7be5829db0a0c
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQ0UyOjI4NUNFMDo2NTEzMzY6ODE0MzZGOjY5NzU3RjJBIiwidmlzaXRvcl9pZCI6IjY0NDUyMjM0NDU5NDMxMjM3NTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmac847313232250575c587aea18fbb2a5bb2299d88cfdd97b7b440a26e306975bd5
hovercard-subject-tagissue:517702608
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/wython/wython.github.io/8/issue_layout
twitter:imagehttps://opengraph.githubassets.com/317377518e85246e87b569b8588ebcfbd4c9c8b7ba8efa2b0454897203f5a998/wython/wython.github.io/issues/8
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/317377518e85246e87b569b8588ebcfbd4c9c8b7ba8efa2b0454897203f5a998/wython/wython.github.io/issues/8
og:image:alt一个react项目 这是一篇关于搭建react项目的基础文章。我决定一个react项目包含前端工程化部分和react技术栈部分。对于前端工程化,采用webpack做工程化是主流的方式。react的技术栈会用到redux和react-router。 webpack的职责 webpack的功能是模块化打包工具。 使用webpack 4 所以,直接使用babel是可以编译react的jsx的,但是...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernamewython
hostnamegithub.com
expected-hostnamegithub.com
None4a4bf5f4e28041a9d2e5c107d7d20b78b4294ba261cab243b28167c16a623a1f
turbo-cache-controlno-preview
go-importgithub.com/wython/wython.github.io git https://github.com/wython/wython.github.io.git
octolytics-dimension-user_id15258919
octolytics-dimension-user_loginwython
octolytics-dimension-repository_id142893945
octolytics-dimension-repository_nwowython/wython.github.io
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id142893945
octolytics-dimension-repository_network_root_nwowython/wython.github.io
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release488b30e96dfd057fbbe44c6665ccbc030b729dde
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://patch-diff.githubusercontent.com/wython/wython.github.io/issues/8#start-of-content
https://patch-diff.githubusercontent.com/
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwython%2Fwython.github.io%2Fissues%2F8
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwython%2Fwython.github.io%2Fissues%2F8
Sign up https://patch-diff.githubusercontent.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=wython%2Fwython.github.io
Reloadhttps://patch-diff.githubusercontent.com/wython/wython.github.io/issues/8
Reloadhttps://patch-diff.githubusercontent.com/wython/wython.github.io/issues/8
Reloadhttps://patch-diff.githubusercontent.com/wython/wython.github.io/issues/8
wython https://patch-diff.githubusercontent.com/wython
wython.github.iohttps://patch-diff.githubusercontent.com/wython/wython.github.io
Notifications https://patch-diff.githubusercontent.com/login?return_to=%2Fwython%2Fwython.github.io
Fork 0 https://patch-diff.githubusercontent.com/login?return_to=%2Fwython%2Fwython.github.io
Star 10 https://patch-diff.githubusercontent.com/login?return_to=%2Fwython%2Fwython.github.io
Code https://patch-diff.githubusercontent.com/wython/wython.github.io
Issues 14 https://patch-diff.githubusercontent.com/wython/wython.github.io/issues
Pull requests 0 https://patch-diff.githubusercontent.com/wython/wython.github.io/pulls
Actions https://patch-diff.githubusercontent.com/wython/wython.github.io/actions
Projects 0 https://patch-diff.githubusercontent.com/wython/wython.github.io/projects
Security 0 https://patch-diff.githubusercontent.com/wython/wython.github.io/security
Insights https://patch-diff.githubusercontent.com/wython/wython.github.io/pulse
Code https://patch-diff.githubusercontent.com/wython/wython.github.io
Issues https://patch-diff.githubusercontent.com/wython/wython.github.io/issues
Pull requests https://patch-diff.githubusercontent.com/wython/wython.github.io/pulls
Actions https://patch-diff.githubusercontent.com/wython/wython.github.io/actions
Projects https://patch-diff.githubusercontent.com/wython/wython.github.io/projects
Security https://patch-diff.githubusercontent.com/wython/wython.github.io/security
Insights https://patch-diff.githubusercontent.com/wython/wython.github.io/pulse
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/wython/wython.github.io/issues/8
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/wython/wython.github.io/issues/8
一个react项目https://patch-diff.githubusercontent.com/wython/wython.github.io/issues/8#top
reacthttps://github.com/wython/wython.github.io/issues?q=state%3Aopen%20label%3A%22react%22
工程化https://github.com/wython/wython.github.io/issues?q=state%3Aopen%20label%3A%22%E5%B7%A5%E7%A8%8B%E5%8C%96%22
https://github.com/wython
https://github.com/wython
wythonhttps://github.com/wython
on Nov 5, 2019https://github.com/wython/wython.github.io/issues/8#issue-517702608
webpack devtoolhttps://webpack.docschina.org/configuration/devtool
https://user-images.githubusercontent.com/15258919/68285456-4634bd80-00ba-11ea-95d6-d8fd0e21c625.png
https://user-images.githubusercontent.com/15258919/78096640-b7c82c00-740c-11ea-86be-30415c458422.png
@importhttps://github.com/import
@typeshttps://github.com/types
reacthttps://github.com/wython/wython.github.io/issues?q=state%3Aopen%20label%3A%22react%22
工程化https://github.com/wython/wython.github.io/issues?q=state%3Aopen%20label%3A%22%E5%B7%A5%E7%A8%8B%E5%8C%96%22
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.