大家都不看的總集篇: 從零開始的大前端築基之旅(深刻淺出,持續更新~)
以爲不錯就順手點個贊吧~javascript
寫前端一年多了,用的都是大佬建好的架子,還沒本身從頭建個項目,如今開始踩坑。css
項目大致包括如下幾部分html
首先,新建個文件夾basic-react-app
。名字不是重點,你高興就好。 而後,使用 npm init
初始化項目,依據提示,一路回車下去前端
$basic-react-app npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
// 從這裏開始,使用默認的話回車便可
package name: (basic-react-app)
version: (1.0.0)
description: basic react demo
entry point: (index.js)
test command:
git repository:
keywords:
author: suil
license: (ISC)
About to write to /Users/zhangpengcheng15/Documents/code/temp/basic-react-app/package.json:
{
"name": "basic-react-app",
"version": "1.0.0",
"description": "basic react demo",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "suil",
"license": "ISC"
}
Is this OK? (yes)
複製代碼
如今,你獲得了一個package.json
文件java
而後,使用git init
初始化倉庫,能夠考慮先在遠端初始化倉庫,再拉去到本地。node
$basic-react-app git init
Initialized empty Git repository in /Users/zhangpengcheng15/Documents/code/temp/basic-react-app/.git/
$basic-react-app git:(master) ✗
複製代碼
若是你使用了特殊的命令窗或zsh,應該就能夠看到目錄後面顯示git:(master)
,表明本地倉庫已經建好了。react
彆着急下一步,不要忘記配置gitignore
,不然電腦配置很差會卡頓一陣子。
在根目錄下新建.gitignore
文件,使用編輯器打開,輸入webpack
node_modules
dist
複製代碼
並保存。好了,如今倉庫初始化結束。ios
最後,打開你喜歡的編輯器,好比 vscode
,來建立以下文件結構。git
.
+ |- /src
+ |- /assets
+ |- /less
+ |- /icons
+ |- /components
+ |- /constants
+ |- /static
+ |- /imgs
+ |- /utils
複製代碼
使用
vscode
的同窗,必定要下vscode-icons
插件呀
其中,
好了,文件結構建完成。下面開始安裝 react
React 是一個聲明式,高效且靈活的用於構建用戶界面的 JavaScript 庫。使用 React 能夠將一些簡短、獨立的代碼片斷組合成複雜的 UI 界面,這些代碼片斷被稱做「組件」。
React 認爲渲染邏輯本質上與其餘 UI 邏輯內在耦合,好比,在 UI 中須要綁定處理事件、在某些時刻狀態發生變化時須要通知到 UI,以及須要在 UI 中展現準備好的數據。
React 並無採用將標記與邏輯進行分離到不一樣文件這種人爲地分離方式,而是經過將兩者共同存放在稱之爲「組件」的鬆散耦合單元之中,來實現關注點分離。
使用命令行安裝 react
及 react-dom
npm install react react-dom
或者 yarn add react react-dom
複製代碼
在開始下一步以前,咱們先在目錄中添加一些文件。
在src目錄下,新建index.tsx
和 index.less
,先不用糾結可否被識別或者運行的問題,下一步咱們再來解決它。
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.less'; // 必定要加 './' 表示當前目錄下
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
複製代碼
h1{
color: blue;
}
複製代碼
webpack 是什麼
webpack
是一個現代 JavaScript
應用程序的靜態模塊打包器,當 webpack
處理應用程序時,會遞歸構建一個依賴關係圖,其中包含應用程序須要的每一個模塊,而後將這些模塊打包成一個或多個 bundle
。
webpack 的核心概念
在本地安裝 webpack,接着安裝 webpack-cli(此工具用於在命令行中運行 webpack):
npm install webpack webpack-cli --save-dev
複製代碼
或者
yarn add webpack webpack-cli --dev
當前webpack基於最新的版本
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
複製代碼
在 webpack 4 中,能夠無須任何配置使用,然而大多數項目會須要很複雜的設置,這就是爲何 webpack 仍然要支持 配置文件。
本文目的在於配置一個可用的
react
項目,所以有些配置會一步到位,如需更多webpack知識,請移步 webpack中文網
在根目錄建立一個 webpack.config.js
,寫入以下內容
const path = require('path');
module.exports = {
entry: './src/index.tsx',
mode: "development",
devtool: 'cheap-module-eval-source-map',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
複製代碼
若是 webpack.config.js 存在,則 webpack 命令將默認選擇使用它。使用 --config 選項能夠傳遞任何名稱的配置文件。
對於多入口文件,可使用以下配置
entry: {
index: './src/index.js',
index2: './src/index2.js',
},
output: {
path: path.resolve(__dirname,'dist'), //此處若非絕對路徑,可能報錯
filename: '[name].bundle.js',
},
複製代碼
在上面的配置文件中,咱們使用了入口 entry
和出口 output
兩個概念,相信你也理解這兩個配置的含義。後面咱們會用到另外兩個概念。
mode 配置項,告知 webpack 使用相應模式的內置優化。
mode 支持如下兩個配置:
development:將 process.env.NODE_ENV 的值設置爲 development,啓用 NamedChunksPlugin 和 NamedModulesPlugin
production:將 process.env.NODE_ENV 的值設置爲 production,啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin
簡單來講,*開發環境(development)和生產環境(production)*的構建目標差別很大。將 mode
設置爲development
會啓用一些webpack默認的優化。這裏咱們先設置爲 mode: "development",
devtool
中的一些設置,能夠幫助咱們將編譯後的代碼映射回原始源代碼。不一樣的值會明顯影響到構建和從新構建的速度。
對咱們而言,可以定位到源碼的行便可,所以,綜合構建速度,在開發模式下,devtool
的值設置爲cheap-module-eval-source-map
。
其餘的配置參數可參考devtool,
Babel 是一個 JavaScript 編譯器
ES2015 中的 import 和 export 語句已經被標準化。雖然大多數瀏覽器還沒法支持它們,可是 webpack 卻可以提供開箱即用般的支持。
事實上,webpack 在幕後會將代碼「轉譯」,以便舊版本瀏覽器能夠執行。可是注意的是,webpack 不會更改代碼中除 import 和 export 語句之外的部分。若是咱們須要使用其它 ES2015 特性,須要在 webpack 的 loader 系統中使用了一個像是 Babel 或 Bublé 的轉譯器。
Babel 是一個工具鏈,主要用於將 ECMAScript 2015+ 版本的代碼轉換爲向後兼容的 JavaScript 語法,以便可以運行在當前和舊版本的瀏覽器或其餘環境中。下面列出的是 Babel 能爲你作的事情:
執行下面的指令安裝 babel
系列
yarn add @babel/core @babel/cli @babel/preset-env @babel/preset-react babel-loader --dev
複製代碼
其中,
webpack 最出色的功能之一就是,除了 JavaScript,還能夠經過 loader 引入任何其餘類型的文件。也就是說,以上列出的那些 JavaScript 的優勢(例如顯式依賴),一樣能夠用來構建網站或 web 應用程序中的全部非 JavaScript 內容。
如今,在 webpack 配置對象中,添加 babel-loader 到 module 的 loaders 列表中,,當前配置文件以下
module.exports = {
entry: './src/index.tsx',
mode: "development",
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
複製代碼
我下載了那麼多包,你就用了這一個?你專門解釋的那兩個包呢?
不着急,其餘的包咱們經過設置babel配置文件來使用。在根目錄下新建 .babelrc
文件,輸入以下內容
{
"presets": [
"@babel/env",
"@babel/preset-react"
]
}
複製代碼
既然說到這裏,咱們先還個債,還記得上面新建的 index.tsx
文件麼?webpack不認識tsx文件,瀏覽器也不認識 tsx 文件,那誰來認呢?
固然是babel
了,在7以前的版本中,咱們須要專門的 ts-loader
來轉義 ts
和tsx
類型的文件,可是,如今只須要有babel
就夠了
不管代碼是否具備 ES2015 特性,JSX,TypeScript,仍是其餘瘋狂的自定義————編譯器都知道要作什麼。向 ts-loader、ts-jest、ts-karma、create-react-app-typescript 等等說再見就好啦,使用 Babel 代替它們。
yarn add @babel/preset-typescript --dev
複製代碼
在.babelrc
文件中補充
{
"presets": [
"@babel/env",
"@babel/preset-react",
+ "@babel/preset-typescript"
],
}
複製代碼
好了,到此,ts | tsx 文件可使用babel-loader編譯了,記得修改webpack.config.js
文件,補充 ts | tsx
使用babel-loader
編譯
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
],
複製代碼
對於loader的用法,
test
字段是匹配規則,針對符合規則的文件進行處理。
use
字段有幾種寫法
use: 'babel-loader'
use: ['style-loader', 'css-loader']
use
數組的每一項既能夠是字符串也能夠是一個對象,當咱們須要在webpack
的配置文件中對 loader
進行配置,就須要將其編寫爲一個對象,而且在此對象的 options
字段中進行配置,例如上面 babel-loader
可使用另外一種配置形式rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
},
exclude: /node_modules/
}
]
複製代碼
如今,去還另外一個債,less文件。要讓webpack識別 less
文件,天然是 less-loader
了。
固然,咱們順手也補充 css
文件的識別。
有關 less 及 sass 的選擇,可移步 Sass.vs.Less | 簡介與比較
爲了從 JavaScript 模塊中 import 一個 CSS 文件,你須要在 module 配置中 安裝並添加 style-loader 和 css-loader:
yarn add style-loader css-loader less-loader --dev
複製代碼
webpack.config.js
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
+ {
+ test: /\.css$/,
+ use: [
+ 'style-loader',
+ 'css-loader'
+ ]
+ },
+ {
+ test: /\.less$/,
+ use: [
+ 'style-loader',
+ 'css-loader',
+ 'less-loader'
+ ]
+ }
],
複製代碼
小提示:vscode中,選中
+
號,而後按win + D
,就能夠連續選中加號,最後按刪除就能夠刪除全部的+
號
PostCss是一個樣式處理工具,它經過自定義的插件和工具生態體系來從新定義css。它鼓勵開發者使用規範的css原生語法編寫代碼,而後配置編譯器轉換須要兼容的瀏覽器版本,最後經過編譯將源碼轉換爲目標瀏覽器可用的css代碼。
yarn add postcss-loader autoprefixer --dev
複製代碼
webpack.config.js
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
+ 'postcss-loader',
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
+ 'postcss-loader',
'less-loader'
]
}
],
複製代碼
postcss-loader 是專門用來加瀏覽器前綴的,可是它本身也就只能加個前綴而已,由於它本身不知道哪一個該加,哪一個不應加。因此咱們須要 autoprefixer 來告訴它,哪一個加,哪一個不加。
在根目錄新增postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
複製代碼
在package.json
中補充下列字段,來肯定咱們要支持到哪一步
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%"
]
複製代碼
未雨綢繆,咱們在此安裝另外兩個會用到的loader
yarn add url-loader file-loader --dev
複製代碼
在webpack.config.js
中補充rules規則
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 2048,
}
},
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
複製代碼
Webpack 在啓動後會從配置的入口模塊出發找出全部依賴的模塊,Resolve 配置 Webpack 如何尋找模塊所對應的文件。
建立 import 或 require 的別名,來確保模塊引入變得更簡單。例如,一些位於 src/ 文件夾下的經常使用模塊:
resolve: {
alias: {
'@': path.resolve(__dirname, "src/")
}
}
複製代碼
如此,引用本身封裝的組件或函數就能夠以@
做爲起始,例如
import BaseButton from "./components/Button/BaseButton";
複製代碼
這樣,避免了無止盡的../../../
,並且萬一某個組件切換了目錄,組件裏的外部引用也不須要從新調整,由於它們老是相對於src路徑開始尋找。
請注意,此處只是容許
webpack
打包時識別,要開啓路徑提示,須要配置tsconfig.json
中的path
,文末有附配置代碼
每次文件修改後,從新打包,致使 dist 目錄下的文件愈來愈多怎麼辦?
快使用clean-webpack-plugin
,每次構建自動爲你清理/dist/
目錄,留你想留,清你想清,一鍵配置,呵護懶癌晚期的你
yarn add clean-webpack-plugin --dev
複製代碼
webpack.config.js
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
+ new CleanWebpackPlugin({
+ cleanOnceBeforeBuildPatterns:['**/*', '!store', '!store/**'] // 不刪除store目錄下的文件
+ }),
],
};
複製代碼
注意:本文沒有拆分不一樣環境的配置文件,在本地調試時,請註釋掉這個插件
更多配置移步clean-webpack-plugin
你可能須要一個HtmlWebpackPlugin
,不然,你可能會想,react組件渲染了掛在哪裏呢?找不到的話它會本身造一個Html
模版麼?
並非,我只是由於懶沒有建立模版文件,
當沒有這個插件的時候,每次webpack打包生成的[name].bundle.js
須要手動配置,如今,它解放了你的雙手,你能夠快樂的乾點別的事了。
yarn add html-webpack-plugin --dev
複製代碼
不論你以前有沒有建立,HtmlWebpackPlugin
會默認在輸出目錄
生成 index.html
文件,全部的 bundle 會自動添加到 html 中。
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:['**/*', '!store', '!store/**'] // 不刪除store目錄下的文件
}),
+ new HtmlWebpackPlugin({
+ title: 'Basic react app'
+ })
],
複製代碼
固然,通常來講,咱們有時須要在public
目錄下新建一個index.html
的模版文件,裏面定義了一些咱們定製的內容,但我仍是不想佔用個人雙手在裏面引入打包生成的bundle.js
文件。
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包後的文件名
config: config.template
})
複製代碼
更多功能移步html-webpack-plugin
說了這麼多,終於到了碰見Hello world
的時候了。不然我擔憂你會看不下去。
webpack-dev-server 提供了一個簡單的 web 服務器,而且可以實時從新加載(live reloading)。讓咱們運行如下命令:
yarn add webpack-dev-server --dev
複製代碼
修改配置文件
+ devServer: {
+ port: '3000', //默認是8080
+ publicPath: "http://localhost:3000/dist/",
+ hotOnly: true,
+ contentBase: './dist'
+ },
複製代碼
在package.json中補充腳本
"scripts": {
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
複製代碼
在命令行先執行yarn build
,再執行yarn start
,頁面自動打開 -> 碰見Hello World
雖然咱們使用babel來編譯 ts|tsx
文件,可是,有時候咱們還會懷念ts的類型錯誤檢查,好比
「不!我不會編譯這玩意兒的!你的代碼在42個不一樣的文件中出現異常!」
如何去檢查類型錯誤呢?添加一段 lint 腳原本喚起 TypeScript 編譯器。例如,將 npm test 命令調整爲先檢查類型,而後再繼續運行單元測試。
因爲性能問題,TypeScript 官方決定全面採用 ESLint,甚至把倉庫(Repository)做爲測試平臺,而 ESLint 的 TypeScript 解析器也成爲獨立項目,專一解決雙方兼容性問題。
yarn add eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --dev
複製代碼
同時,咱們是一個react app 項目,因此,你懂的
yarn add eslint-plugin-react eslint-plugin-react-hooks --dev
複製代碼
在根目錄下新建.eslintrc.js
文件,填入以下內容
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module",
project: './tsconfig.json',
},
plugins: [
"react",
"react-hooks",
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
};
複製代碼
總有些文件是不須要檢查的,作人麼,能夠爲難別人,但不能爲難本身,因此,在根目錄建立一個.eslintignore
文件
config/
scripts/
node_modules/
\.eslintrc.js // 幹掉它本身。。。
webpack.config.js
複製代碼
通過考慮,補充 airbnb
規則
yarn add eslint-config-airbnb-typescript eslint-plugin-jsx-a11y eslint-plugin-import --dev
複製代碼
eslintrc.js文件替換爲
extends: [
'airbnb-typescript',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
複製代碼
不要忘了在
vscode
中下載eslint
插件
雖然上述規則通過了檢驗,但總有些對於咱們本身來講是多餘或者缺失的,因此在.eslintrc.js
文件補充 rules字段,用於開啓或關閉某些規則
"rules": {
// 禁止使用 var
'no-var': "error",
// 優先使用 interface 而不是 type
'@typescript-eslint/consistent-type-definitions': [
"error",
"interface"
],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": "off",
}
複製代碼
修改package.json
中script腳本
"scripts": {
"lint": "eslint --ext .ts --ext .tsx src/",
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
複製代碼
執行yarn lint
,而後愉快的扇本身吧。。。。
我在
src/index.tsx
中留了三個錯誤,大概? 你能夠試着改一下
受不了檢查記得禁止一些規則
忽然發現我沒寫怎麼生成tsconfig.json
,兩個方法,
tsc --init
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"outDir": "./dist/",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
// "isolatedModules": true,
// "noEmit": true,
"jsx": "react",
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"@/*":["src/*"]
}
},
"include": [
"src","test",
]
}
複製代碼
配置項不是本文重點,主要是爲了下面的內容。
在typscript中是沒法識別非代碼資源的,因此若是你試圖import
一個svg|png
之類的文件就會提示你cannot find module '.png'
。
custom.d.ts
declare module "*.svg" {
const content: any;
export default content;
}
declare module "*.png" {
const content: any;
export default content;
}
複製代碼
在tsconfig.json中有一個include字段,裏面的內容表示ts須要轉義的內容,將custom.d.ts
文件放到include
字段包含的目錄中,就能夠解決類型不識別的問題。
最後,這裏附上
airbnb
規則傳送門【airbnb】typescript-eslint
規則傳送門【typescript-eslint】本篇教程到此結束,這只是一篇簡明的指導式教程,若是有什麼不對的地方,歡迎在評論中指出,我會及時修改
後續會針對webpack、eslint語法規範專門整理一期,工做較忙,時間就隨緣了~
若是你收穫了新知識,請點個贊吧~
本文收納於: 從零開始的大前端築基之旅(深刻淺出,持續更新~)
推薦閱讀:
三言兩語帶你理解「閉包」|附使用場景
很簡單就能解釋清的東西爲何要多費口舌呢?朝花夕拾,從新介紹繼承與原型鏈
有圖有真相的講解迴流(reflow)與重繪(repaint),KFC與MC
每次這兩個都會被同時說起,關係就好像KFC邊上必定會有MC同樣親密的讓人摸不到頭腦。讓人恍然大悟的詞法做用域及做用域鏈講解
看圖說話纔是王道viewport和1px | 工具人: 這是1px,設計師: 不,這不是
設計我不行,但吵架我在行啊可食用的「css佈局乾貨」,純Html示例,可調試 | 水平、垂直、多列
可觀看,可調試,可帶走,僅此一家,別無分店前端必須掌握的「CSS層疊上下文」講解 | 純手工示例,包教包會
妹子與貓,你要哪一個?
參考文檔