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
Domain: patch-diff.githubusercontent.com
{"@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\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\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-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:5cc45517-579a-6c47-09df-787ff5a57378 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | ECE2:285CE0:651336:81436F:69757F2A |
| html-safe-nonce | 3769e99510c25a2042b27f9b44d63257bc2bfeb232b0e9d2eee7be5829db0a0c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQ0UyOjI4NUNFMDo2NTEzMzY6ODE0MzZGOjY5NzU3RjJBIiwidmlzaXRvcl9pZCI6IjY0NDUyMjM0NDU5NDMxMjM3NTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 847313232250575c587aea18fbb2a5bb2299d88cfdd97b7b440a26e306975bd5 |
| hovercard-subject-tag | issue:517702608 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/wython/wython.github.io/8/issue_layout |
| twitter:image | https://opengraph.githubassets.com/317377518e85246e87b569b8588ebcfbd4c9c8b7ba8efa2b0454897203f5a998/wython/wython.github.io/issues/8 |
| twitter:card | summary_large_image |
| og:image | https://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:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | wython |
| hostname | github.com |
| expected-hostname | github.com |
| None | 4a4bf5f4e28041a9d2e5c107d7d20b78b4294ba261cab243b28167c16a623a1f |
| turbo-cache-control | no-preview |
| go-import | github.com/wython/wython.github.io git https://github.com/wython/wython.github.io.git |
| octolytics-dimension-user_id | 15258919 |
| octolytics-dimension-user_login | wython |
| octolytics-dimension-repository_id | 142893945 |
| octolytics-dimension-repository_nwo | wython/wython.github.io |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 142893945 |
| octolytics-dimension-repository_network_root_nwo | wython/wython.github.io |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 488b30e96dfd057fbbe44c6665ccbc030b729dde |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width