項目github倉庫地址: https://github.com/mecoepcoo/ts-react-boilerplate
這個系列的文章主要講述如何從一個空目錄創建webpack+react+typescript+eslint腳手架,書寫此文時各主要工具的版本爲:javascript
v4
v16.9
v3.5
v7
v6.2
本文涉及的內容大體包含:css
閱讀這個系列的文章須要具有的條件:html
vue
,react
或angular
等任意一種前端框架vue-cli
,create-react-app
,angular-cli
等任意一種腳手架生成工具webpack
的基本原理或用法Why not create-react-app?筆者使用CRA新建項目時,以爲自定義程度不夠。嘗試過
react-app-rewired + customize-cra
的方案,仍是以爲異常繁瑣,並且會消耗額外的維護精力,魯迅說:青年應當有朝氣,敢做爲,遂自行搭建一個 boilerplate 。前端
咱們要從一個空目錄開始,先新建這個目錄,作一些必要的初始化工做:vue
$ mkdir my-react $ cd my-react $ git init $ npm init
新建以下目錄結構:java
react-projectnode
打包配置
public 靜態文件夾
react
源碼目錄
協做開發時,git提交的內容若是沒有規範,就很差管理項目,咱們用 husky + commitlint 來規範git提交。webpack
咱們先在根目錄下創建 .gitignore
文件,忽略不須要要的文件。git
而後安裝工具:
$ npm i -D husky $ npm i -D @commitlint/cli
husky 會爲 git 增長鉤子,在 commit 時執行一系列操做,commitlint 能夠檢查 git message 是否符合規則。
在 package.json
中增長配置以下:
"husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } },
在根目錄新建文件 .commitlintrc.js
,根據具體狀況配置:
module.exports = { parserPreset: { parserOpts: { headerPattern: /^(\w*)(?:\((.*)\))?:\s(.*)$/, headerCorrespondence: ['type', 'scope', 'subject'] } }, rules: { 'type-empty': [2, 'never'], 'type-case': [2, 'always', 'lower-case'], 'subject-empty': [2, 'never'], 'type-enum': [ 2, 'always', ['feat', 'fix', 'update', 'docs', 'style', 'refactor', 'test', 'chore', 'release', 'revert'] ] } }
這樣便可完成配置,具體的使用方法參考 commitlint文檔
安裝react,寫一個react hello, world
如今讓主角 React 登場:
$ npm i react react-dom
新建一個 hello, world
結構,這裏直接用ts書寫:
// src/index.tsx import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import './style.css'; ReactDOM.render(<App />, document.getElementById('root'));
// src/App.tsx import React from 'react'; import './app.css'; const App: React.FC = () => { return (<div>hello, world</div>); }; export default App;
咱們還須要一個html模板:
<!-- public/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8" /> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title>react-app</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html>
完整的結構參考 代碼示例
安裝webpack相關工具:
$ npm i -D webpack webpack-cli webpack-dev-server webpack-merge
在 config 目錄下新建幾個文件:config.js
, webpack.base.js
, webpack.prod.js
, webpack.dev.js
, build.js
先抽取一些通用的配置:
// config/config.js const path = require('path'); module.exports = { assetsRoot: path.resolve(__dirname, '../dist'), assetsDirectory: 'static', publicPath: '/', indexPath: path.resolve(__dirname, '../public/index.html'), };
// config/webpack.base.js const path = require('path'); const webpack = require('webpack'); const config = require('./config'); module.exports = { entry: { app: './src/index.tsx', }, output: { filename: 'js/[name].bundle.js', path: config.assetsRoot, publicPath: config.publicPath }, module: { rules: [ { oneOf: [] } ] }, resolve: { extensions: ['.js', '.json', '.jsx', '.ts', '.tsx'] // 自動判斷後綴名,引入時能夠不帶後綴 }, plugins: [] };
接下來咱們須要讓webpack支持typescript,而且將代碼轉換爲es5,這樣才能在低版本的瀏覽器上運行。
依然是先安裝工具:
$ npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/polyfill $ npm i core-js@2 # babel的按需引入依賴 $ npm i -D @babel/plugin-proposal-class-properties # 可以在class中自動綁定this的指向 $ npm i -D typescript awesome-typescript-loader # 處理ts,主要就靠它 $ npm i -D html-loader html-webpack-plugin # 順便把html的支持作好
用了ts,就要有一個tsconfig配置,在根目錄新建 tsconfig.json
:
{ "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "typeRoots": [ "src/types" // 指定 d.ts 文件的位置,根據具體狀況修改 ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react", "baseUrl": ".", }, "include": [ "src" ], "exclude": [ "./node_modules" ] }
來配一下webpack:
// webpack.base.js const APP_PATH = path.resolve(__dirname, '../src'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module: { rules: [ { oneOf: [ { test: /\.(html)$/, loader: 'html-loader' }, { test: /\.(j|t)sx?$/, include: APP_PATH, use: [ { loader: 'babel-loader', options: { presets: [ '@babel/preset-react', // jsx支持 ['@babel/preset-env', { useBuiltIns: 'usage', corejs: 2 }] // 按需使用polyfill ], plugins: [ ['@babel/plugin-proposal-class-properties', { 'loose': true }] // class中的箭頭函數中的this指向組件 ], cacheDirectory: true // 加快編譯速度 } }, { loader: 'awesome-typescript-loader' } ] }, ] } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: config.indexPath, showErrors: true }), ], optimization: {}
爲了之後開發時引入路徑方便,咱們加個路徑別名的配置,須要改webpack配置和tsconfig兩處:
// webpack.base.js resolve: { extensions: ['.js', '.json', '.jsx', '.ts', '.tsx'], alias: { '@': path.resolve(__dirname, '../src/') // 以 @ 表示src目錄 } },
{ "compilerOptions": { // ... "paths": { "@/*": ["src/*"] } // ... } }
至此,咱們完成了最最基本的webpack配置,但暫時還不能打包。