從零開始使用webpack 4, Babel 7建立一個React專案

騰訊IMWeb團隊發表於2018-11-18

轉自IMWeb社群,作者:黃qiong,原文連結

前言

看到一篇還不錯的文章,翻譯(也不是完全翻譯,還是改動了一點點讓它變得更易理解)了一波,想看原文的移步這裡

順便推薦一下這個小哥的文章都寫的挺好的~。

你會在本篇學到什麼

1.如何安裝配置webpack

2.如何安裝配置babel

3.如何安裝react

4.如何建立兩種React Component --- 容器/展示元件

5.在html檔案中引用webpack生成的bundle檔案

6.如何安裝使用webpack dev server

初始化專案

首先我們先給專案建立一個資料夾 webpack-react-tutorial

mkdir webpack-react-tutorial && cd webpack-react-tutorial

接著在這個資料夾下建立一個src的子資料夾:

mkdir -p src

初始化專案:

npm init -y

如何安裝配置webpack

webpack

webpack是一款非常有用的前端打包工具,瞭解如何使用它是React開發者的基礎,因為webpack可以將React元件轉化成幾乎所有瀏覽器都可以執行的JS code。

讓我們先來安裝它:

npm i webpack --save-dev

你可能會需要webpack-cli,所以也先裝上

npm i webpack-cli --save-dev

接著在package.json裡新增webpack的指令

"scripts": {
  "build": "webpack --mode production"
}
複製程式碼

到目前為止還不需要寫webpack的配置檔案。

下面我們來安裝和配置Babel來編譯我們的程式碼。

初始化Babel

為什麼要使用Babel?

React Component大多是用JS ES6語法來寫的,而有些瀏覽器沒辦法執行ES6的語法,所以就需要工具來將ES6的程式碼轉化成瀏覽器可以執行的程式碼(通常是es5的語法)。

webpack本身是不會做這件事情的,需要靠轉換器:loader。

一個webpack loader作用就是把輸入進去的檔案轉化成指定的檔案格式輸出。其中babel-loader負責將傳入的es6檔案轉化成瀏覽器可以執行的檔案。

babel-loader需要利用Babel,所以需要預先將Babel配置好。

babel preset env:將ES6的程式碼轉成ES5(注意:babel-preset-es2015已經被廢棄了)

2.babel preset react: 將JSX語法編譯成JS

接著安裝這兩個依賴:

npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev

不要忘了配置Babel! 首先要在webpack-react-tutorial資料夾裡新建一個檔案.babelrc,內容為

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}
複製程式碼

到這個時候,就可以寫一小部分webpack的配置檔案了。

建立一個新的檔案webpack.config.js,內容為

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};
複製程式碼

這個webpack的配置很簡單。意思就是所有以.js結尾的檔案都會用babel-loader把ES6編譯轉化成ES5的檔案。

同時它定義了輸入檔案的路徑為 src/index.js,輸出為dist/bundle.js。webpack 4裡這兩行程式碼你不寫也行,webpack會預設幫你加,但是為了程式碼可讀性,我們還是把它加上。

配置完成之後,我們就可以開始寫React 元件了。

寫React元件

這裡會寫兩種React元件:容器、展示元件。如果不瞭解這兩種元件概念的同學可以先了解一下。

簡單來說: 容器跟展示元件是React元件的兩種模式。

容器元件: 一般比較重資料處理的邏輯會寫在這,比如監聽外界傳入(例如redux) state的變化,或者處理元件內部的state,等等。

展示元件:顧名思義,就是僅僅用來展示的。它一般都是一個純箭頭函式,接受容器元件通過props傳來的資料,然後展示我們希望展示的html結構。

在下面的例子中,你會看到它們長啥樣。

在本節中,我們來建立只有text input 的超級簡單的React表單。

首先先把React庫引進來:

npm i react react-dom --save-dev

然後建立兩個子資料夾來分別放React 容器/展示元件

mkdir -p src/js/components/{container,presentational}

接著我們來寫一個容器元件,它有下面的特點

  • 有自己的state
  • 渲染一個html表單

將這個容器元件放在container裡

touch src/js/components/container/FormContainer.js

容器元件的程式碼如下:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class FormContainer extends Component {
  constructor() {
  super();

  this.state = {
      title: ""
  };
  }

  render() {
  return (
  <form id="article-form">
  </form>
  );
  }
}

export default FormContainer;
複製程式碼

到目前為止,這個元件還沒啥用,它只是一個包裹著子展示元件的外殼。

所以我們來定義一下子元件Input吧。

我們知道html input有下列的屬性:

  • type
  • class
  • id
  • value
  • required

所有的這些屬性都由容器元件通過props傳給它,這種元件叫做controlled component。

寫一個react元件,最好給它加上Prop Types,這樣一來可以做輸入的資料型別檢測,二來別人用你的元件,可以很快知道這個元件需要什麼input。

安裝prop-types

npm i prop-types --save-dev

接著寫這個展示元件

import React from "react";
import PropTypes from "prop-types";
const Input = ({ label, text, type, id, value, handleChange }) => (
  <div className="form-group">
    <label htmlFor={label}>{text}</label>
    <input
      type={type}
      className="form-control"
      id={id}
      value={value}
      onChange={handleChange}
      required
    />
  </div>
);
Input.propTypes = {
  label: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
  id: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  handleChange: PropTypes.func.isRequired
};
export default Input;
複製程式碼

到這一步我們就可以在容器元件裡渲染Input這個子元件了

import React, { Component } from "react";
import ReactDOM from "react-dom";
import Input from "../presentational/Input";
class FormContainer extends Component {
  constructor() {
    super();
    this.state = {
      seo_title: ""
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ [event.target.id]: event.target.value });
  }
  render() {
    const { seo_title } = this.state;
    return (
      <form id="article-form">
        <Input
          text="SEO title"
          label="seo_title"
          type="text"
          id="seo_title"
          value={seo_title}
          handleChange={this.handleChange}
        />
      </form>
    );
  }
}
export default FormContainer;
複製程式碼

寫好元件之後,就可以用webpack來打包這些程式碼啦。

由於前面我們已經定義了webpack入口檔案是 ./src/index.js,所以我們先建立一個index.js檔案,在裡面引入React元件

import FormContainer from "./js/components/container/FormContainer";
複製程式碼

寫好之後,激動人心的時刻到了! 我們終於可以通過執行 npm run build 來生成打包檔案,由於我們在配置裡定義了輸出檔案為:dist/bundle.js,所以一切順利的話, 你現在應該可以看到一個新生成的dist檔案,裡面有一個bundle.js檔案。

在HTML檔案引入bundle

為了展示我們的React元件,我們需要讓webpack生成一個html檔案。上面我們生成的bundle.js就會放在這個html檔案的script標籤裡。

webpack需要兩個工具來生成這個html檔案:html-webpack-pluginhtml-loader

首先新增這兩個依賴:

npm i html-webpack-plugin html-loader --save-dev

然後更新webpack的配置檔案

const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader"
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      title: 'Set Up Project',
      filename: "./index.html"
    })
  ]
};
複製程式碼

index.html是我們的模板檔案,裡面定義了React Component需要插入進入的容器<div>create-article-form</div>,不要忘了在FormContainer裡用React.render繫結這個。

<!doctype html>
<html>
  <head>
    <title>Getting Started</title>
  </head>
  <body>
    <div id='create-article-form'>

    </div>
  </body>
</html>
複製程式碼

在./src/js/components/container/FormContainer.js 加上下面的程式碼:

const wrapper = document.getElementById("create-article-form");
wrapper ? ReactDOM.render(<FormContainer />, wrapper) : false;
複製程式碼

最後,在跑一次構建: npm run build

這時候在dist資料夾裡就會看到生成的html檔案,由於html-webpack-plugin,bundle檔案會被自動注入html裡。 在瀏覽器裡開啟./dist/index.html,你會看到這個React表單。

webpack dev Server

目前為止,我們來遺留一個問題:每次修改檔案的時候,都需要重新跑一次編譯

npm run build

這樣是很麻煩的,我們想達到的效果是自動重新編譯。 達到這個目標很簡單,只需要3行配置就可以啟動執行一個開發伺服器。

啟動伺服器之後webpack就會在瀏覽器裡啟動你的應用,而且當你修改儲存程式碼之後,webpack dev server還會自動重新整理瀏覽器的視窗。

在啟動webpack dev server前,需要先安裝npm i webpack-dev-server --save-dev

開啟package.json 加入start script

"scripts": {
  "start": "webpack-dev-server --open --mode development",
  "build": "webpack"
}
複製程式碼

儲存這個檔案,最後在跑這個命令 npm start

你會在你的瀏覽器裡看到你的應用。

接下來你可以隨意修改一下檔案內容,會看到webpack dev server會自動重新整理瀏覽器視窗。

總結

通過上面的學習,我們已經看到如何從零用webpack 與Babel搭建一個React專案,包括

  • 如何安裝配置webpack
  • 如何安裝配置Babel
  • 如何安裝React
  • 如何建立React容器/展示元件
  • 如何在html裡插入bundle檔案
  • 如何安裝和配置webpack dev server

如果你想了解更多webpack 4的知識,可以移步這篇文章

參考文件:Tutorial: How to set up React, Webpack 4, and Babel 7 (2018)

相關文章