手把手從底層搭建react應用(如何自己實現react腳手架)(webpack環境搭建)

先附上原文鏈接 https://blog.usejournal.com/creating-a-react-app-from-scratch-f3c693b84658

在這裏插入圖片描述
React如果脫離我們所熟悉的環境,可能就不會很好的工作了。原因是React中有很多的關鍵字以及語法是node目前支持不了的(作者寫這篇文章的時候是9.3.0版本)。要想很好的運行React,需要進行一系列相當麻煩的設置。對此呢,Facebook已經提供了一套配置選項來快速啓動React應用,那麼老鐵爲啥還要寫這篇文章呢?

我是這麼認爲的,create-react-app雖好,但是它讓你對React應用變得更加的陌生了(至少在你手動使用eject命令之前是這樣的)。當然,還是有很多驅使你自己配置一個react應用的動機,最起碼你可以搞懂它的底層到底是怎麼運作的。可以極大的滿足你的好奇心。

正如我提到的,在你搭建React應用的過程中會有相當多的障礙。第一點是因爲node有很多語法處理不了(比方說import/export以及JSX)。第二點原因是你需要build你的文件或者在開發的過程中爲你的應用啓動服務—尤其是這後一種情況相當的重要。

所幸的是,我們可以通過Babel以及Webpack來解決這些問題。

安裝(Setup)

開始了,第一步創建一個目錄。然後使用 npm init 初始化你的應用並使用你喜愛的編輯器打開它。此時也是使用 git init 進行初始化操作的好時候。在根目錄下創建如下目錄結構
在這裏插入圖片描述
想的再遠一些,我們最終生成的應用在提交的時候會排除掉很多的文件比如node_module。此時我們還可以創建一個.gitignore文件來排除最後的node_modules以及dist文件。(在git bash下使用touch gitignore即可創建)

public目錄用來存放所有靜態資源以及我們最重要的的index.html文件,畢竟react會用它來初始化render我們的app。 下面的代碼是用react文檔中經過小小修改的源碼。放心大膽的粘貼到你的index.html中。(當然要先在public文件夾中創建一個index.html文件)


<!-- sourced from https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html -->
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>React Starter</title>
</head>

<body>
  <div id="root"></div>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <script src="../dist/bundle.js"></script>
</body>

</html>
view rawreact-app-tutorial index.html hosted with ❤ by GitHub

這裏有兩行需要特別留意。一個是div根容器。我們的react 應用可是要掛在裏面

<div id="root"></div>

另一個是

<script src="../dist/bundle.js"></script>

這個文件裏面會寫我們的react代碼。當然你可以隨便取名字,但我這裏就用bundle.js稱呼它好了

到此,我們把我們的HTML頁面弄好了。接下來我們要嚴肅認真起來了哦。接下來我們要做其他一些事情了。首先呢,我們要確保我們的代碼會被編譯,所以我們需要Babel

Babel

繼續運行如下命令

npm install --save-dev @babel/[email protected] @babel/[email protected] @babel/[email protected] @babel/[email protected]

babel-core是主要的babel包,我們進行任何代碼轉換都離不開它。babel-cli允許你通過命令行的方式來進行文件的編譯。preset-reactpreset-env都是用來進行代碼的特殊轉換。在這個例子中,env預設讓我們能夠將ES6+的代碼轉換成傳統js代碼。react預設則是處理JSX相關的轉換問題。

在項目根目錄下,創建一個文件叫做.babelrc 粘入如下代碼 這裏呢 我們要告訴babel 我們要使用env和react這兩個預設。

{
  "presets": ["@babel/env", "@babel/preset-react"]
}

babel還有很多很多插件你可以使用,如果env預設不能滿足你的需要的話。這不是我們所需要擔心的,當然你可以看這裏查看詳情

Webpack

接下來我們需要配置Webpack了,這裏我們還需要安裝一些包並將他們保存爲本地依賴。

npm install --save-dev 
[email protected] [email protected] 
[email protected] [email protected] [email protected] [email protected]

webpack使用loader來處理不同類型的文件來進行打包。它還能幫我們在開發過程中啓動應用服務,並且在代碼進行改變的時候及時刷新頁面。爲了使用這些功能,我們需要安裝不同的loaders以及準備dev-server

在我們的根目錄下創建一個文件叫做webpack.config.js 這個文件會輸出一個記錄webpack配置的對象(Object),如下

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: "./src/index.js",
  mode: "development",
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules|bower_components)/,
        loader: "babel-loader",
        options: { presets: ["@babel/env"] }
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      }
    ]
  },
  resolve: { extensions: ["*", ".js", ".jsx"] },
  output: {
    path: path.resolve(__dirname, "dist/"),
    publicPath: "/dist/",
    filename: "bundle.js"
  },
  devServer: {
    contentBase: path.join(__dirname, "public/"),
    port: 3000,
    publicPath: "http://localhost:3000/dist/",
    hotOnly: true
  },
  plugins: [new webpack.HotModuleReplacementPlugin()]
};

讓我們快速來看一下這個配置文件

entry告訴webpack我們的應用程序從哪兒開始以及從哪裏開始打包我們的文件。接下來的這行
**mode: “development”,**告訴webpack我們正在以開發模式運行,這使我們不必在運行開發服務器時添加模式標誌

module對象定義你導出的javascript模塊如何轉換以及那些文件要根據給定的rules進行轉換

我們的第一條規則是轉換ES6以及JSX語法。test和exclude是用來匹配文件的條件。在這個例子中,它會匹配node_module
s和bower_components之外的所有目錄。接下來我們要知道webpack上去使用babel來轉換我們的js以及jsx文件(test中定義的規則),最後我們告訴webpack使用env中的預設。

接下來的規則是用來處理css的。因爲我們這裏並沒有用到pre或者post css等高級功能,我們只需要確保加入style-loader以及css-loader到use屬性中。css-loader需要依賴style-loader才能工作。

resolve屬性告訴我們 哪些類型的文件要進行處理,這也允許我們在導入modules的時候不用寫擴展名。

output屬性告訴webpack我們打包之後的代碼在哪裏輸出。publicPath屬性定義了我們打包後的文件應該跑到哪個目錄裏。同時告訴webpack-dev-server從哪裏去啓動我們的服務

這個publicPath屬性是一個特殊的屬性 ,它可以幫助我們進行dev-server操作。他可以定義我們的公共url的目錄,起碼webpack-dev-server會很關心這一點。如果設置錯了,就會報404錯誤。

最後我們在devServer屬性中啓動webpack-dev-server服務。這裏並沒有太多的要求。只要標出我們的靜態資源放那兒(比方說我們的index.html)以及我們要在哪個端口啓動該服務。你可以看到devServer也有一個publicPath,這裏的publicPath是爲了告訴server我們打包後的文件在哪兒

最後需要留心的是 output.publicPath 和 devServer.publicPath是不一樣的。重要的事情說三遍。

最後呢 爲了實現熱更新,及時響應我們的changes 只需要在devServer中將hotOnly設置爲true 當然我們還需要實例化我們的HMR插件(Hot Module Replacement)

大功告成了

接下來看React代碼了

React

首先我們需要額外安裝兩個依賴包 [email protected] 以及 [email protected]

我們需要告訴Reactapp 我們要把reactapp掛在到哪個文件(這裏是index.html)
在src目錄下創建一個index.js文件
粘入以下代碼

import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(<App />, document.getElementById("root"));

ReactDom.render 告訴react渲染什麼,在哪兒渲染。這裏我們將要渲染一個叫做APP(馬上就要創建了)的組件,渲染到我們index.html中的一個div中。

現在在src中創建另外一個文件 叫做App.js 粘入以下代碼(如果你習慣使用create-react-app的話,這段代碼你應該比較熟悉,這是一個react組件)

import React, { Component} from "react";
import "./App.css";

class App extends Component{
  render(){
    return(
      <div className="App">
        <h1> Hello, World! </h1>
      </div>
    );
  }
}

export default App;

接下來我們再加點兒css src目錄下創建一個App.css


.App {
  margin: 1rem;
  font-family: Arial, Helvetica, sans-serif;
}

你最終的代碼結構看起來是這個樣子的
在這裏插入圖片描述
最後我們可以執行webpack-dev-server --mode development 命令啓動我們的服務。當然我建議你把這個放到package.json中的start命令裏面

(令人憤怒的結果搞到現在跑不起來)
問題出在哪裏?!!!!!

檢查之後發現自己少執行了 沒有安裝[email protected] 以及 [email protected]
以及配置babelrc 這個文件裏面寫了個才能在webpack裏面用

Finishing HMR

如果你現在啓動服務,當你做了內容更改之後,需要刷新瀏覽器才能看到效果,我們想讓瀏覽器內容自動改變怎麼辦?

emm HMR需要知道替換什麼,目前我們並沒有給它任何東西。因此,我們要使用react團隊提供給我們的一個包:
[email protected]
你可以按照慣例安裝好它

你可以安全的將react-hot-loader作爲常規依賴項安裝而不是開發以來項,因爲他可確保不會再生產環境執行並且佔用的空間很小。

接下來 在app.js中引入 react-hot-loader 將代碼更改如下

import React, { Component} from "react";
import {hot} from "react-hot-loader";
import "./App.css";

class App extends Component{
  render(){
    return(
      <div className="App">
        <h1> Hello, World! </h1>
      </div>
    );
  }
}

export default hot(module)(App);

現在當你更改內容的時候,按下保存 瀏覽器就會自動刷新了

最後一些細節

你可能注意到一些有趣或者說驚訝的事情,當你啓動項目的時候 你在dist目錄中看不到編譯之後的文件。 這是因爲webpack-dev-server將打包後的文件在內存當中運行了,一旦服務停止,文件就消失了。所以要想生成build之後的文件。我們需要好好的利用webpack。 要在package.json文件中添加一條build指令 webpack --mode development 你可以用生產來代替開發。但是如果你忘記寫–mode 它會自動執行後一種情況並且給你一個警告。

以上的內容幾乎涵蓋了你在開發react應用中的所有內容,而不需要去觸碰craete-react-app 當然 還有很多的東西要添加。比方說,webpack無法處理圖片,但是我們有處理圖片所需的loader。將這個任務留給你,

我希望這篇文章能讓你對react-app架構搭建帶來一些啓發。關於babel以及webpack我沒有太深入,但是建議你不放過本文的任何一個鏈接。這兩個工具乍一看令人生畏,但他們可以讓你的開發水平提升一個質的飛躍!

如果你還搞不懂,這裏有github項目。你也可以查看更老版本的實現(這個可能有點難)。或者在twitter上打招呼

這篇文章寫於2018.4.24
軟件包版本 2018.5.13
反饋webpack-dev-server的bug修復 2018.6.16
反饋對React以及軟件包的更新 2018.9.23

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章