霍爾筆記

全端網站設計範例:前端專案建立

2022-03-20 約 1,251 字 --

本篇為「全端網站架構」中的前端範例及細節。

所需工具及準備

  • Node.js,此專案使用 v14.15.0
  • Yarn,或 npm,此專案指令將使用 yarn

建立 React 專案

我們將安裝 React 搭配 TypeScript,並且手動安裝套件(沒有使用如 create-react-app 這類的 toolchains)。這裡的建立過程大多參考一篇 Medium 的文章(參考資料 1)

並且搭配 Babel, Webpack, Prettier, ESLint。

首先,初始化

$ mkdir client && cd client # 在根目錄建立 client 資料夾
$ yarn init # 初始化,產生 package.json
$ yarn add react react-dom # 新增 npm 套件
$ yarn add -D typescript @types/react @types/react-dom # 新增 typescript 相關套件,-D 表示安裝在 devDependencies
$ mkdir src && mkdir src/public # 新增 src, src/public 資料夾
$ touch src/index.tsx # 建立程式進入點
$ touch src/public/index.html # 建立網頁進入點

再來建立網頁進入點,剛剛透過指令建立的 src/public/index.html 就是將要丟給瀏覽器的目錄文件,程式碼如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

比較需要注意的是 body 下的 div,id 必須為 "root",也就是接下來用 ReactDOM 去渲染時為了取得此 dom 所需要的 id。

然後,建立程式進入點。接下來便要實際把 React 的程式碼加上,編輯 src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<div>Hello, World!</div>, document.getElementById('root'));

設定 TypeScript

$ touch tsconfig.json # 新增 TypeScript 設定檔

編輯此設定檔

{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": ["dom", "esnext"],
    "jsx": "react-jsx",
    "noEmit": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "allowJs": true,
    "checkJs": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"]
}

設定 Sass,讓 Styling 更簡潔

安裝 Sass

$ yarn add -D sass sass-loader

這裡我們採用 .scss 的格式來撰寫 style,新增 scss 檔案

$ touch src/index.scss

編輯其內容

div {
  color: red; // 測試樣式是否應用成功,顯示的文字是否為紅色
}

設定 Babel,編譯程式碼

安裝 Babel

$ yarn add -D \
  @babel/core @babel/cli @babel/preset-env \
  @babel/preset-typescript @babel/preset-react \
  @babel/runtime @babel/plugin-transform-runtime

其中 @babel/core @babel/cli @babel/preset-env 是 Babel 基本必需,而 @babel/runtime @babel/plugin-transform-runtime 則是使用 async-await 會需要加上的。

再來是設定 Babel,透過 .babelrc.json 這支設定檔

$ touch .babelrc.json

編輯其內容

{
  "presets": ["@babel/preset-env", ["@babel/preset-react", { "runtime": "automatic" }], "@babel/preset-typescript"],
  "plugins": [["@babel/plugin-transform-runtime", { "regenerator": true }]]
}

設定 Webpack,打包程式碼

安裝 Webpack

$ yarn add -D \
  webpack webpack-cli webpack-dev-server \
  style-loader css-loader babel-loader \
  html-webpack-plugin clean-webpack-plugin

再來是設定 Webpack,新增 webpack.config.js 這支檔案,作為 Webpack 的進入點

$ touch webpack.config.js

編輯其內容

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: path.resolve(__dirname, 'src', 'index.tsx'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        use: ['babel-loader'],
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
        type: 'asset/inline',
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx'],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './src/public/index.html'),
    }),
    new CleanWebpackPlugin(),
  ],
  devServer: {
    port: 3000,
    hot: 'only',
    compress: true,
    open: true,
  },
};

設定 Prettier,美化程式碼

安裝 Prettier

$ yarn add -D prettier eslint-config-prettier eslint-plugin-prettier

其中 eslint 開頭的套件是為了讓接下來要安裝的 eslint 能和 prettier 一起使用(不會因為 prettier 的設定而使得 linter conflict)。 再來,新增 prettier 的設定檔。

$ touch .prettierrc.json

編輯其內容

{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true,
  "printWidth": 120
}

設定 ESLint,檢查程式碼

安裝 ESLint

$ yarn add -D \
  eslint \
  eslint-plugin-react \
  eslint-plugin-react-hooks \
  eslint-plugin-jsx-a11y \
  eslint-plugin-import \
  @typescript-eslint/parser \
  @typescript-eslint/eslint-plugin

再來新增 ESLint 的設定檔

$ touch .eslintrc.json

編輯其內容

{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2020,
    "sourceType": "module",
    "ecmaFeatures": { "jsx": true }
  },
  "settings": {
    "react": { "version": "detect" }
  },
  "extends": [
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:import/typescript",
    "plugin:jsx-a11y/recommended",
    "plugin:prettier/recommended"
  ],
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": ["error"],
    "@typescript-eslint/no-var-requires": "off",
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "react/prop-types": "off",
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "@typescript-eslint/explicit-module-boundary-types": "off"
  }
}

新增要執行的 Scripts

回到 package.json 設定檔,新增 scripts,加上執行專案的指令

{
  "scripts": {
    "start": "webpack serve --config webpack.config.js --env env=development",
    "build": "webpack --config webpack.config.js --env env=production",
    "lint": "eslint \"./src/**/*.{js,jsx,ts,tsx,json}\"",
    "format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\""
  }
}

.gitignore

將一般需要忽略的檔案寫入 .gitignore

# dependencies
/node_modules

# production
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

執行專案

$ yarn start # 啟動 dev server,並在 http://localhost:3000 看到成果
$ yarn build # 建置,在 dist 資料夾中看到成果

參考資料

  1. A Complete Guideline to Creating a Modern React App With TypeScript From Scratch

修訂記錄

2022-03-20 - 新增 SCSS 相關設定

全端網站設計 #fullstack