1. 程式人生 > >使用webpack搭建react+antd專案

使用webpack搭建react+antd專案

目前網路上關於react和antd的教程有很多,在構建專案階段大多用create-react-app,dva等腳手架工具進行搭建,使用工具固然方便,卻總感覺沒能真正完全掌握這門技術,於是自己嘗試從頭搭建了一個專案

1.環境

    本機使用v8.9.4版本的node,開發工具為Visual Studio Code

2.初始化專案

在專案目錄下執行命令 npm init 初始化專案,在生成的 package.json 檔案中新增以下依賴並執行 npm install 

"dependencies": {
    "antd": "^3.10.1"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.2",
    "babel-plugin-import": "^1.9.1",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^1.0.0",
    "eslint": "^5.7.0",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-react": "^7.11.1",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.5.2",
    "react-dev-utils": "^6.0.5",
    "react-dom": "^16.5.2",
    "react-router-dom": "^4.3.1",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  }

    當然也可以使用npm install手動單獨下載對應依賴,但有些依賴必須指定版本,否則會有衝突。在專案目錄下建立如下資料夾

src用於放置react元件,public用於放置靜態檔案,dist放置編譯目標檔案,config用於放置配置檔案

3.配置webpack

在config中建立webpack配置檔案,任意命名,我這裡命名為webpack.config.js。建立用於控制路徑的配置檔案,我這裡命名為paths.js

'use strict';
const path = require('path');
const fs = require('fs');

const appDirectory = fs.realpathSync(process.cwd());
const resolveAppPath = relativePath => path.resolve(appDirectory, relativePath);

module.exports = {
    mainJs:resolveAppPath('src/main.js'),
    html:resolveAppPath('public/index.html'),
    buildPath:resolveAppPath('dist'),
};

paths.js檔案用於配置在編譯時可能用到的一些路徑,並將其轉化為絕對路徑,這裡匯入了三個路徑

1.mainJs:入口檔案,可以理解為我們的靜態頁面在未編譯時所引入的唯一js檔案,這也是react官方推薦的模式

2.html:靜態頁面路徑

3.biildPath:編譯完成後的檔案應該放置的目錄

const path = require('path');
const paths = require('./paths');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: paths.mainJs,
    output: {
        filename: 'bundle-[hash].js',
        path: paths.buildPath
        },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },{
                 test: /\.css$/, 
                 use: ['style-loader', 'css-loader'] 
            },{ 
                test: /\.(png|jpg|jpeg|gif)$/, 
                use: 'url-loader' 
            },
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: paths.html,
            inject: true
        })
    ]
  };

entry選項用於指定入口檔案,,可以理解為我們的靜態頁面在未編譯時所引入的唯一js檔案

output選項用於指定編譯結果,filename設定編譯完成的檔名稱,使用[hash]將編譯完成的js檔案加上雜湊碼,防止瀏覽器快取,path指定js檔案放置目錄

需要注意的是除了使用babel-loader對js檔案的語法進行轉換之外,還要用style-loader和css-loader對css檔案進行轉換,否則在使用antd的樣式時會報錯,使用HtmlWebpackPlugin在編譯時往html檔案中插入編譯後的js檔案

對於babel的配置主要有兩種方式,一種是在專案根目錄下建立.babelrc檔案

{
    "presets": [
      "es2015",
      "react"
    ],
    "plugins": ["transform-class-properties",["import", {
      "libraryName": "antd",
      "libraryDirectory": "es",
      "style": "css"
    }]]
  }

加入transform-class-properties外掛可以使用屬性初始化器語法,不用在建構函式中定義屬性,同時配置babel-plugin-import,實現antd的按需引入

4.測試

在src目錄下新建page目錄,建立index.js檔案,編寫一個測試元件,這裡用antd官方文件上的演示程式碼

import React from 'react';
import { Menu, Icon, Switch } from 'antd';

const { SubMenu } = Menu;

class Sider extends React.Component {
  state = {
    mode: 'inline',
    theme: 'light',
  }

  changeMode = (value) => {
    this.setState({
      mode: value ? 'vertical' : 'inline',
    });
  }

  changeTheme = (value) => {
    this.setState({
      theme: value ? 'dark' : 'light',
    });
  }

  render() {
    return (
      <div>
        <Switch onChange={this.changeMode} /> Change Mode
        <span className="ant-divider" style={{ margin: '0 1em' }} />
        <Switch onChange={this.changeTheme} /> Change Theme
        <br />
        <br />
        <Menu
          style={{ width: 256 }}
          defaultSelectedKeys={['1']}
          defaultOpenKeys={['sub1']}
          mode={this.state.mode}
          theme={this.state.theme}
        >
          <Menu.Item key="1">
            <Icon type="mail" />
            Navigation One
          </Menu.Item>
          <Menu.Item key="2">
            <Icon type="calendar" />
            Navigation Two
          </Menu.Item>
          <SubMenu key="sub1" title={<span><Icon type="appstore" /><span>Navigation Three</span></span>}>
            <Menu.Item key="3">Option 3</Menu.Item>
            <Menu.Item key="4">Option 4</Menu.Item>
            <SubMenu key="sub1-2" title="Submenu">
              <Menu.Item key="5">Option 5</Menu.Item>
              <Menu.Item key="6">Option 6</Menu.Item>
            </SubMenu>
          </SubMenu>
          <SubMenu key="sub2" title={<span><Icon type="setting" /><span>Navigation Four</span></span>}>
            <Menu.Item key="7">Option 7</Menu.Item>
            <Menu.Item key="8">Option 8</Menu.Item>
            <Menu.Item key="9">Option 9</Menu.Item>
            <Menu.Item key="10">Option 10</Menu.Item>
          </SubMenu>
        </Menu>
      </div>
    );
  }
}

export default Sider;

建立router資料夾,在其中建立router.js檔案,編寫路由

import React from 'react';
import {HashRouter,Route,Switch,Link} from 'react-router-dom'

import Sider from '../page/index'

export default class AppRouter extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <HashRouter>
                <div id="wrapper">
                    <Route path="/" component={Sider}/>
                </div>
            </HashRouter>
        )
    }
}

在入口檔案main.js中引入

import React, { Component } from 'react';
import { render } from 'react-dom';
import AppRouter from './router/router'

render(
    <AppRouter/>,
    document.getElementById('root')
);

命令列執行webpack --config ./config/webpack.config.js(在package.json檔案中配置 "build":"webpack --config ./config/webpack.config.js" 可直接使用npm run build),在dist目錄下會出現編譯後的html檔案和js檔案,直接在瀏覽器開啟,結果如下

完成專案搭建