搭建本身的React+Typescript環境(一)

前言

前陣子在本身學習React,最開始上手使用的creat-react-app來建立本身的項目,2版本以後的create-react-app已經支持了不少功能,好比sass、數據mock、typescript支持等等,也升級了相關依賴babel、webpack到一個最新的版本,具體能夠參照Create React App 中文文檔,可是它將項目的webpack配置等內容給藏起來了,想要本身配置的話還要npm run eject纔可見,不過對於我這種初學者已經足夠了,可是本着折騰的精神,在掘金看了好多大佬的配置文章,終於折騰出一個本身的項目模板,若是有什麼問題或者不對的地方,但願大佬們能及時指出,最後有項目地址~javascript

第二篇生產開發環境配置已經寫完:搭建本身的React+Typescript環境(二)css

項目簡介

主要的依賴以及版本html

  • webpack4+
  • babel7+
  • typescript3+
  • react16.8+
  • antd3+
  • react-router5+
  • eslint5+

初始化項目

  1. 建立一個目錄,名字按本身喜愛來
    mkdir react-ts-template
    cd react-ts-template
    複製代碼
  2. 初始化項目,填寫項目信息
    yarn init -y 或者 npm init -y
    複製代碼

安裝webpack

yarn add webpack -D 或者 npm i webpack -D
yarn add webpack-cli -D 或者 npm i webpack-cli -D
複製代碼
  • webpack也能夠全局安裝,不過要注意配置PATH
  • webpack4將命令行相關的操做抽離到了webpack-cli中,好比init、migrate、serve等等,不過都沒用過

安裝完畢後在根目錄新建build文件夾,並新建一個webpack.common.js文件,用來存放webpack的公共配置vue

mkdir build
cd build
touch webapck.common.js
複製代碼

而後在webpack.common.js中簡單的配置入口(entry)跟輸出(output)。java

const path = require('path'); module.exports={ entry: path.join(__dirname, '../src/index.js'), output: { filename: 'bundle.js', path: path.join(__dirname, '../dist') } } 複製代碼

接着在根目錄下再新建src文件夾,用來存放主要代碼,並新建index.js,隨便寫點東西。node

console.log('Hello World'); 複製代碼

在package.json中加入一個腳本,並在控制檯中運行它npm run buildreact

"scripts": {
    "build": "webpack --config build/webpack.common.js"
}
複製代碼

以後會發現生成了一個dist文件夾,而且還有一個bundle.js,同時控制檯還會有報錯webpack

WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ 複製代碼

webpack4中提供了 mode 配置選項,告知 webpack 使用相應模式的內置優化,上面這個警告寫着若是不提供mode,webpack將會使用production模式。咱們把scripts修改一下。git

"scripts": {
    "build": "webpack --config build/webpack.common.js --mode production"
}
複製代碼

這樣的webpack簡單的打包功能就有了。es6

Bable

Bable這裏使用的是7版本,與以前版本不一樣的是安裝依賴時的包名,像babel-core、babel-preset-env、babel-polyfill等,名字已經更換成了@babel/core、@babel/preset-env、@babel/polyfill,這裏先安裝主要的包。

yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader -D
複製代碼

而後在根目錄下新建一個babel.config.js,這個配置文件跟.babelrc.js是有區別的,根據官網來看babel.config.js是項目級別的一個配置,詳細信息能夠參照官網 Config Files,在其中添加以下內容:

module.exports = { presets: [ '@babel/preset-env', '@babel/preset-react' ], plugins: [] } 複製代碼

修改webpack.common.js,增長 js 文件的 loader 配置,以後還會改。

module: { rules: [{ test: /\.js$/, use: ['babel-loader'], include: path.join(__dirname, '../src') }] } 複製代碼

React

接下來加入React,也是最重要的部分。

yarn add react react-dom
複製代碼

修改 src/index.js 中的內容

import React from 'react'; import ReactDom from 'react-dom'; ReactDom.render(<div>Hello React!</div>, document.getElementById('root')); 複製代碼

而後在根目錄下新建一個public文件夾,並在裏面新建一個index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>React-TS-Tempalte</title> </head> <body> <div id="root"></div> </body> </html> 複製代碼

想要 webpack 能以這個html爲模板,還須要一個html-webpack-plugin插件,安裝它yarn add html-webpack-plugin -D並在webpack.common.js中增長以下配置,這也是用到的第一個插件:

const HtmlWebpackPlugin = require('html-webpack-plugin'); ... plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: 'public/index.html', inject: true }) ] 複製代碼

讓咱們打包後打開dist下的index.html看看效果,成功地展現了Hello React。

 

 

開發環境配置

接下來安裝 webpack-dev-server 來啓動一個簡單的服務器。

yarn add webpack-dev-server -D
複製代碼

修改webpack.common.config.js,增長webpack-dev-server的配置。

devServer: {
    host: 'localhost', port: 3000, historyApiFallback: true, overlay: { //當出現編譯器錯誤或警告時,就在網頁上顯示一層黑色的背景層和錯誤信息 errors: true }, inline: true, hot: true } 複製代碼

接下來須要在package.json中增長一個script

"scripts": { "dev": "webpack-dev-server --config build/webpack.common.js --mode development --open" } 複製代碼

在控制檯中輸入npm run dev,即可以在http://localhost:3000 中看到啓動的項目。

Typescript

下面加入Typescript依賴,關鍵的依賴包就是 typescript,不過還須要安裝對應的types:@types/react、@types/react-dom。

yarn add typescript @types/react @types/react-dom -D
複製代碼

接下來須要把以前的 js、jsx 文件替換成對應的 ts、tsx,同時還須要對應的loader,可使用 ts-loader 以及以前安裝過的 babel-loader,這裏使用以前安裝的 babel-loader,在webpack.common.js中添加配置:

rules: [
  {
    test: /\.(j|t)sx?$/, include: [resolve('../src')], use: [ { loader: 'babel-loader' } ], // 排除node_modules底下的 exclude: /node_modules/ } ] 複製代碼

修改 webpack 的入口配置

module.exports={ entry: path.join(__dirname, '../src/index.tsx') } 複製代碼

不要忘記把src下的index.js改爲index.tsx

配置tsconfig.json,這個文件也是使用ts時很關鍵的一個文件,下面是官網的推薦配置。

{
  "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"
  ]
}
複製代碼

CSS配置

這裏咱們須要用到 style-loadercss-loader,先安裝它們

  • css-loader使你可以使用相似@import 和 url(...)的方法實現 require()的功能;
  • style-loader將全部的計算後的樣式加入頁面中; 兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的JS文件中。
yarn add style-loader css-loader -D
複製代碼

而後在webpack.common.js中添加相應的規則

{
    test: /\.css$/, // 正則匹配文件路徑 exclude: /node_modules/, use: [ // 注意loader生效是從下往上的 'style-loader', 'css-loader' ] } 複製代碼

接着在webpack.common.js中配置resolve.extensions,來自動解析肯定的擴展。

resolve: {
    extensions: ['.ts', '.tsx', '.js', 'jsx'] } 複製代碼

在根目錄下新建一個index.css,以及App.tsx,並在index.tsx中引入它們

// index.css
.app {
    background-color: red;
}

// App.tsx
import * as React from 'react' class App extends React.Component { render() { return ( <div className="app"> Hello React </div> ) } } export default App // index.tsx import React from 'react' import ReactDOM from 'react-dom' import App from './App' import './index.css' ReactDOM.render(<App />, document.getElementById('root')) 複製代碼

啓動後即可以看到設置的紅色背景

加入Sass

若是想要在編寫樣式時使用sass的語法,就須要安裝相應的loader。

yarn add sass-loader node-sass -D
複製代碼

注意:node-sass安裝時可能會遇到網絡問題,須要使用淘寶鏡像源。

安裝完成後在webpack.common.js中加入 .scss 文件的規則

{
    test: /\.scss$/, include: path.join(__dirname, '../src'), use: [ 'style-loader', 'css-loader', 'sass-loader' ] } 複製代碼

接下來咱們把根目錄下的index.css改爲index.scss,不要忘記index.tsx中引入的文件後綴也要修改,項目啓動後發現能夠成功解析scss文件。

配置公共sass屬性

既然已經可使用sass進行更加簡便的css代碼編寫,那麼咱們也能夠將經常使用的一些樣式代碼和sass變量寫入公共文件中,當使用的時候就能夠直接引入使用。

在src目錄下新建styles文件夾,而後新建一個var.scss文件用於存放樣式變量。 以後在var.scss文件裏寫入一個顏色變量和一個樣式:

$red: red; @mixin ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 複製代碼

而後在剛纔的index.scss文件中引入它。

@import './styles/var.scss'; .app{ background: $red; .aps { width: 50px; @include ellipsis; } } 複製代碼

這樣配置以後還存在一個優化上的問題,若是須要在不一樣的層級引入var.scss就要根據每一個文件夾的路徑相對來引入很是麻煩,那麼咱們可否作到只須要@import var.scss就行呢?答案是能夠的,咱們能夠經過配置loader的屬性includePaths進行路徑優化,修改webpack.common.js。

{
    test: /\.scss$/, include: path.join(__dirname, '../src'), use: [ 'style-loader', 'css-loader', { loader: 'sass-loader', options: { includePaths: [path.join(__dirname, '../src/styles')] } } ] } 複製代碼

這樣以後咱們在引入的時候只須要寫文件名稱便可。

@import 'var.scss'; 複製代碼

加入PostCSS

什麼是PostCSS呢?借用官方的話:

PostCSS 是一個容許使用 JS 插件轉換樣式的工具。 這些插件能夠檢查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 編譯還沒有被瀏覽器普遍支持的先進的 CSS 語法,內聯圖片,以及其它不少優秀的功能。

它提供了不少經常使用的插件

  • 提早使用先進的 CSS 特性
    • autoprefixer 添加了 vendor 瀏覽器前綴,它使用 Can I Use 上面的數據。
    • postcss-preset-env 容許你使用將來的 CSS 特性。
  • 更佳的 CSS 可讀性
    • precss 囊括了許多插件來支持相似 Sass 的特性,好比 CSS 變量,套嵌,mixins 等。
  • 圖片和字體
    • postcss-assets 能夠插入圖片尺寸和內聯文件。
    • postcss-sprites 能生成雪碧圖。

...還有不少,具體能夠查看PostCSS中文Readme

這裏主要用autoprefixer,首先安裝postcss-loader

yarn add postcss-loader autoprefixer -D
複製代碼

以後在根目錄下新建一個postcss.config.js文件,並寫入:

module.exports = { plugins: [ require('autoprefixer') ] } 複製代碼

最後須要在webpack.common.js的樣式相關插件的 css-loader 以後加上配置,以scss爲例

{
    test: /\.scss$/, include: path.join(__dirname, '../src'), use: [ 'style-loader', 'css-loader', 'postcss-loader', // 加了這一行 { loader: 'sass-loader', options: { includePaths: [path.join(__dirname, '../src/styles')] } } ] } 複製代碼

隨便寫點樣式,而後在谷歌控制檯能夠發現,會自動幫你添加 -webkit- 的前綴。

注意若是使用了 postcss-preset-env 這個的話,它會自動安裝 autoprefixer,而且配置了它,就再也不須要配置 autoprefixer

const postcssPresetEnv = require('postcss-preset-env'); module.exports = { plugins: [ postcssPresetEnv(/* pluginOptions */) ] } 複製代碼

CSS Modules優化

CSS Modules 是爲了加入局部做用域和模塊依賴,這裏我沒加入它,能夠代替它的方案也有,好比scoped,以及bem命名方式等,這裏我選擇了bem命名方法,掘金也有關於它的介紹,能夠去看看。

圖片字體等資源加載

首先安裝處理這類資源的加載器

yarn add url-loader file-loader -D
複製代碼

而後在webpack.common.js中加入相關的規則配置

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [ { loader: 'url-loader', options: { //1024 == 1kb //小於10kb時打包成base64編碼的圖片不然單獨打包成圖片 limit: 10240, name: path.join('img/[name].[hash:7].[ext]') } }] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, use: [{ loader: 'url-loader', options: { limit: 10240, name: path.join('font/[name].[hash:7].[ext]') } }] } 複製代碼

ESlint

關於typescript代碼的規範校驗,可選的有tslint和eslint,不過最近官方也推薦往eslint上轉了,因此我這裏使用eslint,安裝相關依賴。

yarn add eslint eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser
複製代碼

若是不使用 hook 的話,就不用裝 eslint-plugin-react-hooks 這個插件了

在根目錄下新建.eslintrc.js,並寫入配置:

module.exports = { extends: [ "eslint:recommended", "plugin:react/recommended" ], parserOptions: { "ecmaVersion": 2019, "sourceType": "module" }, env: { node: true, browser: true, commonjs: true, es6: true }, parser: '@typescript-eslint/parser', plugins: [ "@typescript-eslint", "react-hooks" ], globals: { // 這裏填入你的項目須要的全局變量 // 這裏值爲 false 表示這個全局變量不容許被從新賦值,好比: // React: false, // ReactDOM: false }, settings: { react: { pragma: "React", version: "detect" } }, rules: { // 這裏填入你的項目須要的個性化配置,好比: // // // @fixable 一個縮進必須用兩個空格替代 semi: ['error', 'never'], 'no-console': 'off', 'no-unused-vars': [ 'warn', { vars: 'all', args: 'none', caughtErrors: 'none' } ], 'max-nested-callbacks': 'off', 'react/no-children-prop': 'off', 'typescript/member-ordering': 'off', 'typescript/member-delimiter-style': 'off', 'react/jsx-indent-props': 'off', 'react/no-did-update-set-state': 'off', "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", indent: [ 'off', 2, { SwitchCase: 1, flatTernaryExpressions: true } ] } } 複製代碼

用 VS Code 開發時,應該還須要配置settings.json

"eslint.autoFixOnSave": true, "eslint.validate": [ "javascript", "javascriptreact", { "language": "html", "autoFix": true }, { "language": "vue", "autoFix": true }, { "language": "typescript", "autoFix": true }, { "language": "typescriptreact", "autoFix": true }, ] 複製代碼

AntDesign

antd是阿里家的一款UI組件庫,官方文檔中關於如何引入使用講的很清楚,咱們來配置一下,先安裝須要的依賴,babel-plugin-import 用於按需引入:

yarn add antd
yarn add babel-plugin-import less less-loader -D 
複製代碼

在babel.config.js中增長配置

plugins: [
    ...
    ['import', { libraryName: 'antd', libraryDirectory: 'lib', style: true }] ] 複製代碼

還須要在webpack.common.js中配置less規則

{
    // for ant design test: /\.less$/, include: resolve('../node_modules'), use: [ 'style-loader', 'css-loader', 'postcss-loader', { loader: 'less-loader', options: { javascriptEnabled: true, modifyVars: theme } } ] } 複製代碼

注意 modifyVars: theme 這個是根據官網來的 自定義主題,須要新建一個 theme.js,這個文件的名字本身定義,這裏修改了一下主要顏色,以及 border-radius-base 的值,還有不少配置具體能夠查看官網。

module.exports = { 'primary-color': 'black', 'border-radius-base': '10px' } 複製代碼

以後即可以按照官網實例愉快的使用了。不過打包以後存在一個問題,icons.js佔了很大的一部分,這裏使用github上的大佬給出的解決方案。

在src下新建一個icons.ts,裏面只寫用到的icon

export { default as DownOutline } from '@ant-design/icons/lib/outline/DownOutline' 複製代碼

而後配置別名,這裏就將在ts中使用別名的方式一塊介紹了。在 webpack.common.js 中的 resolve 項中增長下面配置,跟icon有關的是第二行。

alias: { '@': resolve('../src'), "@ant-design/icons/lib/dist$": resolve('../src/icons.ts'), '@components': resolve('../src/components'), '@img': resolve('../src/assets/img') } 複製代碼

還須要在tsconfig.json中增長配置:

"paths": { "@/*": ["src/*"], "@ant-design/icons/lib/dist$": ["src/icons.js"], "@components/*": ["src/components/*"], "@img/*": ["src/assets/img/*"] } 複製代碼

更新babel配置

以前加了 typescript 等依賴,如今來更新一下 babel 的配置,來支持咱們後面可能會用到的功能,好比裝飾器以及路由的動態引入。

yarn add @babel/preset-typescript @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import -D
複製代碼

修改 babel.config.js

module.exports = { presets: [ '@babel/preset-env', '@babel/preset-typescript', '@babel/preset-react' ], plugins: [ ['import', { libraryName: 'antd', libraryDirectory: 'lib', style: true }], ['@babel/plugin-proposal-decorators', { legacy: true }], ['@babel/plugin-proposal-class-properties', { loose: true }], '@babel/plugin-syntax-dynamic-import' ] } 複製代碼

React-router

router使用最新的5版本,而後路由懶加載使用官方例子中的loadable,首先仍是安裝依賴

yarn add react-router-dom
yarn add @loadable/component @types/loadable__component @types/react-router-dom -D
複製代碼

讓咱們在 App.tsx 中使用它們

import * as React from 'react' import { HashRouter as Router, Route, Link } from "react-router-dom" import loadable from '@loadable/component' const HomeComponent = loadable(() => import(/* webpackChunkName: "home" */ './views/Home')) const AboutComponent = loadable(() => import(/* webpackChunkName: "about" */ './views/About')) class App extends React.Component { render() { return ( <div className="app"> <Router> <ul> <li> <Link to="/">To Home</Link> </li> <li> <Link to="/about">To About</Link> </li> </ul> <Route exact path='/' component={HomeComponent}></Route> <Route path='/about' component={AboutComponent}></Route> </Router> <p className="aps">hahahaahhahhahahaha</p> </div> ) } } export default App 複製代碼

更多

到這裏基本的功能已經具有了,接下來還須要一些優化以及拆分開發和生產環境的配置,篇幅有點長了,放到下一篇文章裏寫吧。

最後附上地址 項目地址,若是有不對的地方但願各位指出,感謝。

做者:GLaDOS 連接:https://juejin.im/post/5d0ccc9ff265da1b934e0a44 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索