把茶当水喝 發表於 2019-7-9 10:17:00

搭建自己的React+Typescript环境(一)

<div>
<div>
<h2 class="heading" data-id="heading-0">前言</h2>
<p>前阵子在自己学习React,最开始上手使用的<code>creat-react-app</code>来创建自己的项目,2版本之后的create-react-app已经支持了很多功能,比如sass、数据mock、typescript支持等等,也升级了相关依赖babel、webpack到一个最新的版本,具体可以参照Create React App 中文文档,但是它将项目的webpack配置等内容给藏起来了,想要自己配置的话还要<code>npm run eject</code>才可见,不过对于我这种初学者已经足够了,但是本着折腾的精神,在掘金看了好多大佬的配置文章,终于折腾出一个自己的项目模板,如果有什么问题或者不对的地方,希望大佬们能及时指出,最后有项目地址~</p>
<p>第二篇生产开发环境配置已经写完:搭建自己的React+Typescript环境(二)</p>
<h2 class="heading" data-id="heading-1">项目简介</h2>
<p>主要的依赖以及版本</p>
<ul>
<li>webpack4+</li>
<li>babel7+</li>
<li>typescript3+</li>
<li>react16.8+</li>
<li>antd3+</li>
<li>react-router5+</li>
<li>eslint5+</li>
</ul>
<h2 class="heading" data-id="heading-2">初始化项目</h2>
<ol>
<li>创建一个目录,名字按自己喜好来
<pre><code class="hljs shell copyable" lang="shell">mkdir react-ts-template
cd react-ts-template
<span class="copy-code-btn">复制代码</span></code></pre>
</li>
<li>初始化项目,填写项目信息
<pre><code class="hljs bash copyable" lang="bash">yarn init -y 或者 npm init -y
<span class="copy-code-btn">复制代码</span></code></pre>
</li>
</ol>
<h2 class="heading" data-id="heading-3">安装webpack</h2>
<pre><code class="hljs bash copyable" lang="bash">yarn add webpack -D 或者 npm i webpack -D
yarn add webpack-cli -D 或者 npm i webpack-cli -D
<span class="copy-code-btn">复制代码</span></code></pre>
<ul>
<li>webpack也可以全局安装,不过要注意配置PATH</li>
<li>webpack4将命令行相关的操作抽离到了webpack-cli中,比如init、migrate、serve等等,不过都没用过</li>
</ul>
<p>安装完毕后在根目录新建build文件夹,并新建一个webpack.common.js文件,用来存放webpack的公共配置</p>
<pre><code class="hljs shell copyable" lang="shell">mkdir build
cd build
touch webapck.common.js
<span class="copy-code-btn">复制代码</span></code></pre>
<p>然后在webpack.common.js中简单的配置入口(entry)跟输出(output)。</p>
<pre><code class="hljs bash copyable" lang="bash">const path = require(<span class="hljs-string">'path');
module.exports={
entry: path.join(__dirname, <span class="hljs-string">'../src/index.js'),
output: {
    filename: <span class="hljs-string">'bundle.js',
    path: path.join(__dirname, <span class="hljs-string">'../dist')
}
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></code></pre>
<p>接着在根目录下再新建src文件夹,用来存放主要代码,并新建index.js,随便写点东西。</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">console.log(<span class="hljs-string">'Hello World');
<span class="copy-code-btn">复制代码</span></span></span></code></pre>
<p>在package.json中加入一个脚本,并在控制台中运行它<code>npm run build</code></p>
<pre><code class="hljs json copyable" lang="json">"scripts": {
    "build": "webpack --config build/webpack.common.js"
}
<span class="copy-code-btn">复制代码</span></code></pre>
<p>之后会发现生成了一个dist文件夹,并且还有一个bundle.js,同时控制台还会有报错</p>
<pre><code class="hljs bash copyable" lang="bash">WARNING <span class="hljs-keyword">in configuration
The <span class="hljs-string">'mode' option has not been <span class="hljs-built_in">set, webpack will fallback to <span class="hljs-string">'production' <span class="hljs-keyword">for this value. Set <span class="hljs-string">'mode' option to <span class="hljs-string">'development' or <span class="hljs-string">'production' to <span class="hljs-built_in">enable defaults <span class="hljs-keyword">for each environment.
You can also <span class="hljs-built_in">set it to <span class="hljs-string">'none' to <span class="hljs-built_in">disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>webpack4中提供了 <code>mode</code> 配置选项,告知 webpack 使用相应模式的内置优化,上面这个警告写着如果不提供mode,webpack将会使用<code>production</code>模式。我们把scripts修改一下。</p>
<pre><code class="hljs json copyable" lang="json">"scripts": {
    "build": "webpack --config build/webpack.common.js --mode production"
}
<span class="copy-code-btn">复制代码</span></code></pre>
<p>这样的webpack简单的打包功能就有了。</p>
<h2 class="heading" data-id="heading-4">Bable</h2>
<p>Bable这里使用的是7版本,与之前版本不同的是安装依赖时的包名,像babel-core、babel-preset-env、babel-polyfill等,名字已经更换成了@babel/core、@babel/preset-env、@babel/polyfill,这里先安装主要的包。</p>
<pre><code class="hljs shell copyable" lang="shell">yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>然后在根目录下新建一个babel.config.js,这个配置文件跟.babelrc.js是有区别的,根据官网来看babel.config.js是项目级别的一个配置,详细信息可以参照官网 Config Files,在其中添加如下内容:</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports = {
<span class="hljs-attr">presets: [
    <span class="hljs-string">'@babel/preset-env',
    <span class="hljs-string">'@babel/preset-react'
],
<span class="hljs-attr">plugins: []
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></code></pre>
<p>修改webpack.common.js,增加 js 文件的 loader 配置,之后还会改。</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module: {
    <span class="hljs-attr">rules: [{
      <span class="hljs-attr">test: <span class="hljs-regexp">/\.js$/,
      <span class="hljs-attr">use: [<span class="hljs-string">'babel-loader'],
      <span class="hljs-attr">include: path.join(__dirname, <span class="hljs-string">'../src')
    }]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-5">React</h2>
<p>接下来加入React,也是最重要的部分。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add react react-dom
<span class="copy-code-btn">复制代码</span></code></pre>
<p>修改 src/index.js 中的内容</p>
<pre><code class="hljs jsx copyable" lang="jsx"><span class="hljs-keyword">import React <span class="hljs-keyword">from <span class="hljs-string">'react';
<span class="hljs-keyword">import ReactDom <span class="hljs-keyword">from <span class="hljs-string">'react-dom';

ReactDom.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div&gt;Hello React!<span class="hljs-tag">&lt;/<span class="hljs-name">div&gt;, <span class="hljs-built_in">document.getElementById(<span class="hljs-string">'root'));
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>然后在根目录下新建一个public文件夹,并在里面新建一个index.html</p>
<pre><code class="hljs bash copyable" lang="bash">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=<span class="hljs-string">"UTF-8"&gt;
&lt;meta name=<span class="hljs-string">"viewport" content=<span class="hljs-string">"width=device-width, initial-scale=1.0"&gt;
&lt;meta http-equiv=<span class="hljs-string">"X-UA-Compatible" content=<span class="hljs-string">"ie=edge"&gt;
&lt;title&gt;React-TS-Tempalte&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=<span class="hljs-string">"root"&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></code></pre>
<p>想要 webpack 能以这个html为模板,还需要一个<code>html-webpack-plugin</code>插件,安装它<code>yarn add html-webpack-plugin -D</code>并在webpack.common.js中增加如下配置,这也是用到的第一个插件:</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-keyword">const HtmlWebpackPlugin = <span class="hljs-built_in">require(<span class="hljs-string">'html-webpack-plugin');
...
plugins: [
    <span class="hljs-keyword">new HtmlWebpackPlugin({
      <span class="hljs-attr">filename: <span class="hljs-string">'index.html',
      <span class="hljs-attr">template: <span class="hljs-string">'public/index.html',
      <span class="hljs-attr">inject: <span class="hljs-literal">true
    })
]
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>让我们打包后打开dist下的index.html看看效果,成功地展示了Hello React。</p>
<p>&nbsp;</p>
<img class="lazyload inited loaded" alt="" data-src="https://user-gold-cdn.xitu.io/2019/6/23/16b84ad0d703d616?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" data-width="385" data-height="204">
<p>&nbsp;</p>
<h2 class="heading" data-id="heading-6">开发环境配置</h2>
<p>接下来安装 <code>webpack-dev-server</code> 来启动一个简单的服务器。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add webpack-dev-server -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>修改webpack.common.config.js,增加webpack-dev-server的配置。</p>
<pre><code class="hljs js copyable" lang="js">devServer: {
    <span class="hljs-attr">host: <span class="hljs-string">'localhost',
    <span class="hljs-attr">port: <span class="hljs-number">3000,
    <span class="hljs-attr">historyApiFallback: <span class="hljs-literal">true,
    <span class="hljs-attr">overlay: {
      <span class="hljs-comment">//当出现编译器错误或警告时,就在网页上显示一层黑色的背景层和错误信息
      errors: <span class="hljs-literal">true
    },
    <span class="hljs-attr">inline: <span class="hljs-literal">true,
    <span class="hljs-attr">hot: <span class="hljs-literal">true
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>接下来需要在package.json中增加一个script</p>
<pre><code class="hljs bash copyable" lang="bash"><span class="hljs-string">"scripts": {
    <span class="hljs-string">"dev": <span class="hljs-string">"webpack-dev-server --config build/webpack.common.js --mode development --open"
}
<span class="copy-code-btn">复制代码</span></span></span></span></code></pre>
<p>在控制台中输入<code>npm run dev</code>,便可以在<code>http://localhost:3000</code> 中看到启动的项目。</p>
<h2 class="heading" data-id="heading-7">Typescript</h2>
<p>下面加入Typescript依赖,关键的依赖包就是 typescript,不过还需要安装对应的types:@types/react、@types/react-dom。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add typescript @types/react @types/react-dom -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>接下来需要把之前的 js、jsx 文件替换成对应的 ts、tsx,同时还需要对应的loader,可以使用 <code>ts-loader</code> 以及之前安装过的 <code>babel-loader</code>,这里使用之前安装的 <code>babel-loader</code>,在webpack.common.js中添加配置:</p>
<pre><code class="hljs js copyable" lang="js">rules: [
{
    <span class="hljs-attr">test: <span class="hljs-regexp">/\.(j|t)sx?$/,
    <span class="hljs-attr">include: ,
    <span class="hljs-attr">use: [
      {
      <span class="hljs-attr">loader: <span class="hljs-string">'babel-loader'
      }
    ],
    <span class="hljs-comment">// 排除node_modules底下的
    exclude: <span class="hljs-regexp">/node_modules/
}
]
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>修改 webpack 的入口配置</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports={
<span class="hljs-attr">entry: path.join(__dirname, <span class="hljs-string">'../src/index.tsx')
}
<span class="copy-code-btn">复制代码</span></span></span></span></code></pre>
<p>不要忘记把src下的index.js改成index.tsx</p>
<p>配置tsconfig.json,这个文件也是使用ts时很关键的一个文件,下面是官网的推荐配置。</p>
<pre><code class="hljs json copyable" lang="json">{
"compilerOptions": {
    /* Basic Options */
    "target": "es5",                        /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "esnext",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],                                        /* Specify library files to be included in the compilation. */
    "allowJs": true,                        /* Allow javascript files to be compiled. */
    "jsx": "react",                           /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "sourceMap": true,                        /* Generates corresponding '.map' file. */
    "outDir": "./dist",                     /* Redirect output structure to the directory. */
    "isolatedModules": true,                  /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "strict": true,                           /* Enable all strict type-checking options. */
    "noImplicitThis": true,                   /* Raise error on 'this' expressions with an implied 'any' type. */
    "noImplicitReturns": true,                /* Report error when not all code paths in function return a value. */
    "moduleResolution": "node",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "baseUrl": ".",                     /* Base directory to resolve non-absolute module names. */
    "paths": {},                                        /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    "allowSyntheticDefaultImports": true,   /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "experimentalDecorators": true,         /* Enables experimental support for ES7 decorators. */
},
"include": [
    "src"
],
"exclude": [
    "node_modules"
]
}
<span class="copy-code-btn">复制代码</span></code></pre>
<h2 class="heading" data-id="heading-8">CSS配置</h2>
<p>这里我们需要用到 <code>style-loader</code>、<code>css-loader</code>,先安装它们</p>
<ul>
<li>css-loader使你能够使用类似@import 和 url(...)的方法实现 require()的功能;</li>
<li>style-loader将所有的计算后的样式加入页面中; 二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。</li>
</ul>
<pre><code class="hljs bash copyable" lang="bash">yarn add style-loader css-loader -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>然后在webpack.common.js中添加相应的规则</p>
<pre><code class="hljs bash copyable" lang="bash">{
    <span class="hljs-built_in">test: /\.css$/, // 正则匹配文件路径
    exclude: /node_modules/,
    use: [
      // 注意loader生效是从下往上的
      <span class="hljs-string">'style-loader',
      <span class="hljs-string">'css-loader'
    ]
}
<span class="copy-code-btn">复制代码</span></span></span></span></code></pre>
<p>接着在webpack.common.js中配置resolve.extensions,来自动解析确定的扩展。</p>
<pre><code class="hljs bash copyable" lang="bash">resolve: {
    extensions: [<span class="hljs-string">'.ts', <span class="hljs-string">'.tsx', <span class="hljs-string">'.js', <span class="hljs-string">'jsx']
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></code></pre>
<p>在根目录下新建一个index.css,以及App.tsx,并在index.tsx中引入它们</p>
<pre><code class="hljs bash copyable" lang="bash">// index.css
.app {
    background-color: red;
}

// App.tsx
import * as React from <span class="hljs-string">'react'

class App extends React.Component {
<span class="hljs-function"><span class="hljs-title">render() {
    <span class="hljs-built_in">return (
      &lt;div className=<span class="hljs-string">"app"&gt;
      Hello React
      &lt;/div&gt;
    )
}
}
<span class="hljs-built_in">export default App

// index.tsx
import React from <span class="hljs-string">'react'
import ReactDOM from <span class="hljs-string">'react-dom'
import App from <span class="hljs-string">'./App'
import <span class="hljs-string">'./index.css'

ReactDOM.render(&lt;App /&gt;, document.getElementById(<span class="hljs-string">'root'))

<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>启动后便可以看到设置的红色背景</p>
<h2 class="heading" data-id="heading-9">加入Sass</h2>
<p>如果想要在编写样式时使用sass的语法,就需要安装相应的loader。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add sass-loader node-sass -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>注意:node-sass安装时可能会遇到网络问题,需要使用淘宝镜像源。</p>
<p>安装完成后在webpack.common.js中加入 .scss 文件的规则</p>
<pre><code class="hljs bash copyable" lang="bash">{
    <span class="hljs-built_in">test: /\.scss$/,
    include: path.join(__dirname, <span class="hljs-string">'../src'),
    use: [
      <span class="hljs-string">'style-loader',
      <span class="hljs-string">'css-loader',
      <span class="hljs-string">'sass-loader'
    ]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></code></pre>
<p>接下来我们把根目录下的index.css改成index.scss,不要忘记index.tsx中引入的文件后缀也要修改,项目启动后发现可以成功解析scss文件。</p>
<h3 class="heading" data-id="heading-10">配置公共sass属性</h3>
<p>既然已经可以使用sass进行更加简便的css代码编写,那么我们也可以将常用的一些样式代码和sass变量写入公共文件中,当使用的时候就可以直接引入使用。</p>
<p>在src目录下新建styles文件夹,然后新建一个var.scss文件用于存放样式变量。 之后在var.scss文件里写入一个颜色变量和一个样式:</p>
<pre><code class="hljs scss copyable" lang="scss"><span class="hljs-variable">$red: red;
@<span class="hljs-keyword">mixin ellipsis {
<span class="hljs-attribute">overflow: hidden;
<span class="hljs-attribute">text-overflow: ellipsis;
<span class="hljs-attribute">white-space: nowrap;
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></code></pre>
<p>然后在刚才的index.scss文件中引入它。</p>
<pre><code class="hljs scss copyable" lang="scss">@<span class="hljs-keyword">import <span class="hljs-string">'./styles/var.scss';

<span class="hljs-selector-class">.app{
<span class="hljs-attribute">background: <span class="hljs-variable">$red;
<span class="hljs-selector-class">.aps {
    <span class="hljs-attribute">width: <span class="hljs-number">50px;
    @<span class="hljs-keyword">include ellipsis;
}
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这样配置之后还存在一个优化上的问题,如果需要在不同的层级引入var.scss就要根据每个文件夹的路径相对来引入非常麻烦,那么我们能否做到只需要@import var.scss就行呢?答案是可以的,我们可以通过配置loader的属性includePaths进行路径优化,修改webpack.common.js。</p>
<pre><code class="hljs js copyable" lang="js">{
    <span class="hljs-attr">test: <span class="hljs-regexp">/\.scss$/,
    <span class="hljs-attr">include: path.join(__dirname, <span class="hljs-string">'../src'),
    <span class="hljs-attr">use: [
      <span class="hljs-string">'style-loader',
      <span class="hljs-string">'css-loader',
      {
      <span class="hljs-attr">loader: <span class="hljs-string">'sass-loader',
      <span class="hljs-attr">options: {
          <span class="hljs-attr">includePaths:
      }
      }
    ]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这样之后我们在引入的时候只需要写文件名称即可。</p>
<pre><code class="hljs bash copyable" lang="bash">@import <span class="hljs-string">'var.scss';
<span class="copy-code-btn">复制代码</span></span></code></pre>
<h2 class="heading" data-id="heading-11">加入PostCSS</h2>
<p>什么是PostCSS呢?借用官方的话:</p>
<blockquote>
<p>PostCSS 是一个允许使用 JS 插件转换样式的工具。 这些插件可以检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片,以及其它很多优秀的功能。</p>
</blockquote>
<p>它提供了很多常用的插件</p>
<ul>
<li>提前使用先进的 CSS 特性
<ul>
<li>autoprefixer 添加了 vendor 浏览器前缀,它使用 Can I Use 上面的数据。</li>
<li>postcss-preset-env 允许你使用未来的 CSS 特性。</li>
</ul>
</li>
<li>更佳的 CSS 可读性
<ul>
<li>precss 囊括了许多插件来支持类似 Sass 的特性,比如 CSS 变量,套嵌,mixins 等。</li>
</ul>
</li>
<li>图片和字体
<ul>
<li>postcss-assets 可以插入图片尺寸和内联文件。</li>
<li>postcss-sprites 能生成雪碧图。</li>
</ul>
</li>
</ul>
<p>...还有很多,具体可以查看PostCSS中文Readme</p>
<p>这里主要用autoprefixer,首先安装postcss-loader</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add postcss-loader autoprefixer -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>之后在根目录下新建一个postcss.config.js文件,并写入:</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports = {
<span class="hljs-attr">plugins: [
    <span class="hljs-built_in">require(<span class="hljs-string">'autoprefixer')
]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></code></pre>
<p>最后需要在webpack.common.js的样式相关插件的 css-loader 之后加上配置,以scss为例</p>
<pre><code class="hljs bash copyable" lang="bash">{
    <span class="hljs-built_in">test: /\.scss$/,
    include: path.join(__dirname, <span class="hljs-string">'../src'),
    use: [
      <span class="hljs-string">'style-loader',
      <span class="hljs-string">'css-loader',
      <span class="hljs-string">'postcss-loader', // 加了这一行
      {
      loader: <span class="hljs-string">'sass-loader',
      options: {
          includePaths:
      }
      }
    ]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></code></pre>
<p>随便写点样式,然后在谷歌控制台可以发现,会自动帮你添加 <code>-webkit-</code> 的前缀。</p>
<p>注意如果使用了 <code>postcss-preset-env</code> 这个的话,它会自动安装 <code>autoprefixer</code>,并且配置了它,就不再需要配置 <code>autoprefixer</code>。</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-keyword">const postcssPresetEnv = <span class="hljs-built_in">require(<span class="hljs-string">'postcss-preset-env');
<span class="hljs-built_in">module.exports = {
<span class="hljs-attr">plugins: [
    postcssPresetEnv(<span class="hljs-comment">/* pluginOptions */)
]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-12">CSS Modules优化</h2>
<p>CSS Modules 是为了加入局部作用域和模块依赖,这里我没加入它,可以代替它的方案也有,比如scoped,以及bem命名方式等,这里我选择了bem命名方法,掘金也有关于它的介绍,可以去看看。</p>
<h2 class="heading" data-id="heading-13">图片字体等资源加载</h2>
<p>首先安装处理这类资源的加载器</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add url-loader file-loader -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>然后在webpack.common.js中加入相关的规则配置</p>
<pre><code class="hljs js copyable" lang="js">{
    <span class="hljs-attr">test: <span class="hljs-regexp">/\.(png|jpe?g|gif|svg)(\?.*)?$/,
    <span class="hljs-attr">use: [
      {
      <span class="hljs-attr">loader: <span class="hljs-string">'url-loader',
      <span class="hljs-attr">options: {
      <span class="hljs-comment">//1024 == 1kb
      <span class="hljs-comment">//小于10kb时打包成base64编码的图片否则单独打包成图片
      limit: <span class="hljs-number">10240,
      <span class="hljs-attr">name: path.join(<span class="hljs-string">'img/..')
      }
    }]
},
{
    <span class="hljs-attr">test: <span class="hljs-regexp">/\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    <span class="hljs-attr">use: [{
      <span class="hljs-attr">loader: <span class="hljs-string">'url-loader',
      <span class="hljs-attr">options: {
      <span class="hljs-attr">limit: <span class="hljs-number">10240,
      <span class="hljs-attr">name: path.join(<span class="hljs-string">'font/..')
      }
    }]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-14">ESlint</h2>
<p>关于typescript代码的规范校验,可选的有tslint和eslint,不过最近官方也推荐往eslint上转了,所以我这里使用eslint,安装相关依赖。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add eslint eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser
<span class="copy-code-btn">复制代码</span></code></pre>
<p>如果不使用 <code>hook</code> 的话,就不用装 <code>eslint-plugin-react-hooks</code> 这个插件了</p>
<p>在根目录下新建.eslintrc.js,并写入配置:</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports = {
<span class="hljs-attr">extends: [
    <span class="hljs-string">"eslint:recommended",
    <span class="hljs-string">"plugin:react/recommended"
],
<span class="hljs-attr">parserOptions: {
    <span class="hljs-string">"ecmaVersion": <span class="hljs-number">2019,
    <span class="hljs-string">"sourceType": <span class="hljs-string">"module"
},
<span class="hljs-attr">env: {
    <span class="hljs-attr">node: <span class="hljs-literal">true,
    <span class="hljs-attr">browser: <span class="hljs-literal">true,
    <span class="hljs-attr">commonjs: <span class="hljs-literal">true,
    <span class="hljs-attr">es6: <span class="hljs-literal">true
},
<span class="hljs-attr">parser: <span class="hljs-string">'@typescript-eslint/parser',
<span class="hljs-attr">plugins: [
    <span class="hljs-string">"@typescript-eslint",
    <span class="hljs-string">"react-hooks"
],
<span class="hljs-attr">globals: {
    <span class="hljs-comment">// 这里填入你的项目需要的全局变量
    <span class="hljs-comment">// 这里值为 false 表示这个全局变量不允许被重新赋值,比如:
    <span class="hljs-comment">// React: false,
    <span class="hljs-comment">// ReactDOM: false
},
<span class="hljs-attr">settings: {
    <span class="hljs-attr">react: {
      <span class="hljs-attr">pragma: <span class="hljs-string">"React",
      <span class="hljs-attr">version: <span class="hljs-string">"detect"
    }
},
<span class="hljs-attr">rules: {
    <span class="hljs-comment">// 这里填入你的项目需要的个性化配置,比如:
    <span class="hljs-comment">//
    <span class="hljs-comment">// // @fixable 一个缩进必须用两个空格替代
    semi: [<span class="hljs-string">'error', <span class="hljs-string">'never'],
    <span class="hljs-string">'no-console': <span class="hljs-string">'off',
    <span class="hljs-string">'no-unused-vars': [
      <span class="hljs-string">'warn',
      {
      <span class="hljs-attr">vars: <span class="hljs-string">'all',
      <span class="hljs-attr">args: <span class="hljs-string">'none',
      <span class="hljs-attr">caughtErrors: <span class="hljs-string">'none'
      }
    ],
    <span class="hljs-string">'max-nested-callbacks': <span class="hljs-string">'off',
    <span class="hljs-string">'react/no-children-prop': <span class="hljs-string">'off',
    <span class="hljs-string">'typescript/member-ordering': <span class="hljs-string">'off',
    <span class="hljs-string">'typescript/member-delimiter-style': <span class="hljs-string">'off',
    <span class="hljs-string">'react/jsx-indent-props': <span class="hljs-string">'off',
    <span class="hljs-string">'react/no-did-update-set-state': <span class="hljs-string">'off',
    <span class="hljs-string">"react-hooks/rules-of-hooks": <span class="hljs-string">"error",
    <span class="hljs-string">"react-hooks/exhaustive-deps": <span class="hljs-string">"warn",
    <span class="hljs-attr">indent: [
      <span class="hljs-string">'off',
      <span class="hljs-number">2,
      {
      <span class="hljs-attr">SwitchCase: <span class="hljs-number">1,
      <span class="hljs-attr">flatTernaryExpressions: <span class="hljs-literal">true
      }
    ]
}
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>用 VS Code 开发时,应该还需要配置settings.json</p>
<pre><code class="hljs bash copyable" lang="bash">    <span class="hljs-string">"eslint.autoFixOnSave": <span class="hljs-literal">true,
    <span class="hljs-string">"eslint.validate": [
      <span class="hljs-string">"javascript",
      <span class="hljs-string">"javascriptreact",
      {
            <span class="hljs-string">"language": <span class="hljs-string">"html",
            <span class="hljs-string">"autoFix": <span class="hljs-literal">true
      },
      {
            <span class="hljs-string">"language": <span class="hljs-string">"vue",
            <span class="hljs-string">"autoFix": <span class="hljs-literal">true
      },
      {
            <span class="hljs-string">"language": <span class="hljs-string">"typescript",
            <span class="hljs-string">"autoFix": <span class="hljs-literal">true
      },
      {
            <span class="hljs-string">"language": <span class="hljs-string">"typescriptreact",
            <span class="hljs-string">"autoFix": <span class="hljs-literal">true
      },
    ]
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-15">AntDesign</h2>
<p>antd是阿里家的一款UI组件库,官方文档中关于如何引入使用讲的很清楚,我们来配置一下,先安装需要的依赖,<code>babel-plugin-import</code> 用于按需引入:</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add antd
yarn add babel-plugin-import less less-loader -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>在babel.config.js中增加配置</p>
<pre><code class="hljs js copyable" lang="js">plugins: [
    ...
    [<span class="hljs-string">'import', {
      <span class="hljs-attr">libraryName: <span class="hljs-string">'antd',
      <span class="hljs-attr">libraryDirectory: <span class="hljs-string">'lib',
      <span class="hljs-attr">style: <span class="hljs-literal">true
    }]
]
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></code></pre>
<p>还需要在webpack.common.js中配置less规则</p>
<pre><code class="hljs js copyable" lang="js">{
    <span class="hljs-comment">// for ant design
    test: <span class="hljs-regexp">/\.less$/,
    <span class="hljs-attr">include: resolve(<span class="hljs-string">'../node_modules'),
    <span class="hljs-attr">use: [
      <span class="hljs-string">'style-loader',
      <span class="hljs-string">'css-loader',
      <span class="hljs-string">'postcss-loader',
      {
      <span class="hljs-attr">loader: <span class="hljs-string">'less-loader',
      <span class="hljs-attr">options: {
          <span class="hljs-attr">javascriptEnabled: <span class="hljs-literal">true,
          <span class="hljs-attr">modifyVars: theme
      }
      }
    ]
   }
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>注意 <code>modifyVars: theme</code> 这个是根据官网来的 自定义主题,需要新建一个 theme.js,这个文件的名字自己定义,这里修改了一下主要颜色,以及 <code>border-radius-base</code> 的值,还有很多配置具体可以查看官网。</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports = {
<span class="hljs-string">'primary-color': <span class="hljs-string">'black',
<span class="hljs-string">'border-radius-base': <span class="hljs-string">'10px'
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></code></pre>
<p>之后便可以按照官网实例愉快的使用了。不过打包之后存在一个问题,icons.js占了很大的一部分,这里使用github上的大佬给出的解决方案。</p>
<p>在src下新建一个icons.ts,里面只写用到的icon</p>
<pre><code class="hljs bash copyable" lang="bash"><span class="hljs-built_in">export { default as DownOutline } from <span class="hljs-string">'@ant-design/icons/lib/outline/DownOutline'
<span class="copy-code-btn">复制代码</span></span></span></code></pre>
<p>然后配置别名,这里就将在ts中使用别名的方式一块介绍了。在 webpack.common.js 中的 <code>resolve</code> 项中增加下面配置,跟icon有关的是第二行。</p>
<pre><code class="hljs bash copyable" lang="bash"><span class="hljs-built_in">alias: {
<span class="hljs-string">'@': resolve(<span class="hljs-string">'../src'),
<span class="hljs-string">"@ant-design/icons/lib/dist$": resolve(<span class="hljs-string">'../src/icons.ts'),
<span class="hljs-string">'@components': resolve(<span class="hljs-string">'../src/components'),
<span class="hljs-string">'@img': resolve(<span class="hljs-string">'../src/assets/img')
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>还需要在tsconfig.json中增加配置:</p>
<pre><code class="hljs bash copyable" lang="bash"><span class="hljs-string">"paths": {
<span class="hljs-string">"@/*": [<span class="hljs-string">"src/*"],
<span class="hljs-string">"@ant-design/icons/lib/dist$": [<span class="hljs-string">"src/icons.js"],
<span class="hljs-string">"@components/*": [<span class="hljs-string">"src/components/*"],
<span class="hljs-string">"@img/*": [<span class="hljs-string">"src/assets/img/*"]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-16">更新babel配置</h2>
<p>之前加了 typescript 等依赖,现在来更新一下 babel 的配置,来支持我们后面可能会用到的功能,比如装饰器以及路由的动态引入。</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add @babel/preset-typescript @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>修改 babel.config.js</p>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-built_in">module.exports = {
<span class="hljs-attr">presets: [
    <span class="hljs-string">'@babel/preset-env',
    <span class="hljs-string">'@babel/preset-typescript',
    <span class="hljs-string">'@babel/preset-react'
],
<span class="hljs-attr">plugins: [
    [<span class="hljs-string">'import', {
      <span class="hljs-attr">libraryName: <span class="hljs-string">'antd',
      <span class="hljs-attr">libraryDirectory: <span class="hljs-string">'lib',
      <span class="hljs-attr">style: <span class="hljs-literal">true
    }],
    [<span class="hljs-string">'@babel/plugin-proposal-decorators', { <span class="hljs-attr">legacy: <span class="hljs-literal">true }],
    [<span class="hljs-string">'@babel/plugin-proposal-class-properties', { <span class="hljs-attr">loose: <span class="hljs-literal">true }],
    <span class="hljs-string">'@babel/plugin-syntax-dynamic-import'
]
}
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-17">React-router</h2>
<p>router使用最新的5版本,然后路由懒加载使用官方例子中的loadable,首先还是安装依赖</p>
<pre><code class="hljs bash copyable" lang="bash">yarn add react-router-dom
yarn add @loadable/component @types/loadable__component @types/react-router-dom -D
<span class="copy-code-btn">复制代码</span></code></pre>
<p>让我们在 App.tsx 中使用它们</p>
<pre><code class="hljs jsx copyable" lang="jsx"><span class="hljs-keyword">import * <span class="hljs-keyword">as React <span class="hljs-keyword">from <span class="hljs-string">'react'
<span class="hljs-keyword">import { HashRouter <span class="hljs-keyword">as Router, Route, Link } <span class="hljs-keyword">from <span class="hljs-string">"react-router-dom"
<span class="hljs-keyword">import loadable <span class="hljs-keyword">from <span class="hljs-string">'@loadable/component'

<span class="hljs-keyword">const HomeComponent = loadable(<span class="hljs-function"><span class="hljs-params">() =&gt; <span class="hljs-keyword">import(<span class="hljs-comment">/* webpackChunkName: "home" */ <span class="hljs-string">'./views/Home'))
<span class="hljs-keyword">const AboutComponent = loadable(<span class="hljs-function"><span class="hljs-params">() =&gt; <span class="hljs-keyword">import(<span class="hljs-comment">/* webpackChunkName: "about" */ <span class="hljs-string">'./views/About'))

<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">App <span class="hljs-keyword">extends <span class="hljs-title">React.<span class="hljs-title">Component {


render() {

    <span class="hljs-keyword">return (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div <span class="hljs-attr">className=<span class="hljs-string">"app"&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Router&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">ul&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">li&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">Link <span class="hljs-attr">to=<span class="hljs-string">"/"&gt;To Home<span class="hljs-tag">&lt;/<span class="hljs-name">Link&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">li&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">li&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">Link <span class="hljs-attr">to=<span class="hljs-string">"/about"&gt;To About<span class="hljs-tag">&lt;/<span class="hljs-name">Link&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">li&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route <span class="hljs-attr">exact <span class="hljs-attr">path=<span class="hljs-string">'/' <span class="hljs-attr">component=<span class="hljs-string">{HomeComponent}&gt;<span class="hljs-tag">&lt;/<span class="hljs-name">Route&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route <span class="hljs-attr">path=<span class="hljs-string">'/about' <span class="hljs-attr">component=<span class="hljs-string">{AboutComponent}&gt;<span class="hljs-tag">&lt;/<span class="hljs-name">Route&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Router&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">p <span class="hljs-attr">className=<span class="hljs-string">"aps"&gt;hahahaahhahhahahaha<span class="hljs-tag">&lt;/<span class="hljs-name">p&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">div&gt;
    )
}
}

<span class="hljs-keyword">export <span class="hljs-keyword">default App
<span class="copy-code-btn">复制代码</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 class="heading" data-id="heading-18">更多</h2>
<p>到这里基本的功能已经具备了,接下来还需要一些优化以及拆分开发和生产环境的配置,篇幅有点长了,放到下一篇文章里写吧。</p>
<p>最后附上地址 项目地址,如果有不对的地方希望各位指出,感谢。</p>
</div>
<br>作者:GLaDOS<br>链接:https://juejin.im/post/5d0ccc9ff265da1b934e0a44<br>来源:掘金<br>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</div><br><br>
来源:https://www.cnblogs.com/ssw-men/p/11155699.html
頁: [1]
查看完整版本: 搭建自己的React+Typescript环境(一)