iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
1
Modern Web

React + D3 的正確姿勢系列 第 11

Day11-React環境架設(Webpack)

前言

今天要來介紹如何手動建立 React.js 的開發環境,今天要介紹的東西需要對 Webpack 有點基礎知識,由於 Webpack 的基本觀念非常多因此筆者在之前有寫了一篇關於 Webpack 的基本觀念文章,有興趣的讀者歡迎先到下方連結處讀完文章後再開始閱讀此篇文章,這樣才會比較容易搞懂今天文章的內容喔!

JS模組化!(套件結合篇)

Webpack loader 設定

這邊主要會介紹幾個筆者常用到的 loader ,由於現在都自己手動設定 Webpack 了所以內部的寫法相當彈性,讀者不一定要按照筆者的方式建立出一樣的開發環境喔!

  • babel-loader

    首先要用到的還是 babel 這個非常強大的轉譯器,畢竟我們寫的 JSX 瀏覽器一定看不懂,必須要靠 babel 幫忙轉譯,但這邊不是單純寫個 babel 就好,這裡必須要用到一個 preset 的功能,透過這個功能可以讓 babel 知道要處理的是 React.js ,這樣才能順利的進行 babel 的轉譯,所以寫法上就會在 use.options.presets 內加上 babel-preset-react 像底下這樣:

    {
      test: /\.js$/,
      exclude: /(node_modules)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-react'],
          plugins: ['syntax-dynamic-import', 'transform-class-properties'],
        },
      },
    },
    

    可以看到筆者還額外增加了 syntax-dynamic-import 以及 transform-class-properties

    • syntax-dynamic-import

      動態 import 檔案,由於 React.js 會運用到大量的檔案引用,透過這個套件就可以進行動態加載了。

    • transform-class-properties

      這個套件是為了解決 ES6 class 中 defaultProps={} 不支援的問題,而筆者在初始化 state 的時候很常直接在 class 內寫上 state = {} ,假如沒有使用這個套件的話, babel 在轉譯的過程中就會出錯,但假如讀者是習慣在 constructor() 內初始化 state 的話,這個套件就可以不用加了。

  • style-loader

    將讀取 CSS 檔後的樣式擺在 HTML style tag 內,設定檔的寫法就參考連結內的 Readme 即可。

  • css-loader

    將利用 ES6 moduleimport 的 CSS 進行讀取,設定檔的寫法就參考連結內的 Readme 即可。

    結合上面兩個 loader 應該可以猜到 style-loader 要擺在 css-loader 前面,因為先讀取檔案再讀取內部的樣式,所以這邊讀者在寫設定檔的時候記得不要擺錯了喔!

  • sass-loader

    還記得最一開始文章介紹的 SCSS 嗎?其實瀏覽器本身是不支援 SCSS 的寫法,因此我們必須要利用 Webpack 內的 sass-loader 進行 SCSS to CSS 的轉譯過程,就好比 ES6 經由 babel 轉成 ES5 的寫法一樣,設定檔的寫法就參考連結內的 Readme 即可。

    讓我們來結合一下上面三個跟 CSS 有關的 loader ,這邊應該也不難猜到 sass-loader 要擺在 css-loader 之後,因為先進行 SCSS to CSS 的轉譯,再讀取轉譯後的檔案最後才是讀取檔案內部的樣式,所以這邊讀者在寫設定檔的時候記得不要擺錯了喔!

  • file-loader

    前面只有講到如何將 CSS 以及 JS 檔進行 import 後的處理,可是上面的 Webpack 圖片還有講到也可以處理圖片檔,這時候就必須要仰賴 file-loader 的幫忙了。

    file-loader 最主要的作用就是將 import 後的圖片進行讀取,設定檔的寫法就參考連結內的 Readme 即可。

  • url-loader

    講完 file-loader 再來就是要講 url-loader 了, url-loader 的功能也是進行圖片的讀取,但其實 url-loaderfile-loader 兩者是差蠻大的。

    url loader 做的事情就是幫圖片檔進行 Base64 的轉換進而加速網頁讀取速度, Base64 簡單來說就是一串非常難讀的字串,而字串的讀取速度永遠比檔案來得快,這也是 url-loader 最主要在做的事情,設定檔的寫法就參考連結內的 Readme 即可。

Webpack chunk 設定

這邊一樣會設定 chunk 畢竟 react 以及 react-dom 不會一直變動,所以可以用個 chunk 來加快之後編譯的速度,寫法就像下面這樣:

optimization: {
  splitChunks: {
    chunks: 'all',
    name: 'vendor',
  },
},

Webpack merge

由於筆者習慣將一份 Webpack 設定檔拆成共用的 webpack.config.js 、開發用的 webpack-dev.js 以及產品用的 webpack-prod.js ,雖然要寫比較多的檔案,但這也會讓整個開發流程切割的更精準一些,為了要將共用檔融合至其他的設定檔,這時候就需要 webpack-merge 了,而 webpack merge 的寫法也很簡單,這邊用個簡單的範例碼來演繹一下:

const webpack = require('webpack')
const merge = require('webpack-merge')
const common = require('./webpack.config.js')

module.exports = merge(common, {
  // write some custom settings
})

Development 設定

這邊一樣會用到 webpack-dev-server ,至於 webpack-dev-server 的指令設定在之前的文章就有介紹過了這邊就不加以贅述,這邊筆者要提供一個蠻好用的 Webpack plugin 叫 webpack-bundle-analyzer ,透過這個插件可以很迅速地知道這個專案到底有共生了哪些肥大的檔案XD

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const webpack = require('webpack')
const merge = require('webpack-merge')
const common = require('./webpack.config.js')

module.exports = merge(common, {
  plugins: [
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'development',
    }),
    new BundleAnalyzerPlugin({ openAnalyzer: false }),
  ],
  devtool: 'source-map',
  devServer: {
    port: 3000,
    contentBase: path.join(__dirname, 'src'),
    // inline: true,
    publicPath: '/dist/',
    historyApiFallback: true,
  },
})

待 webpack-dev-server 跑完之後會看到終端機出現這段文字 Webpack Bundle Analyzer is started at http://127.0.0.1:8888 這時候就可以在瀏覽器上面看到 webpack bundle analyzer 的畫面啦!

看看這個 react-dom 多肥竟然有 904KB ,所以開發的時候一定要設定 chunk 來打包這個檔案,不然每次重新編譯的時候都要跑很久XD

Production 設定

最後就是 Production 的設定,其實這個設定也沒什麼就加個 uglifyjs-webpack-plugin 把檔案做壓縮同時把 Webpack 的打包環境改成 production 而已,寫法會像這樣:

const webpack = require('webpack')
const merge = require('webpack-merge')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const common = require('./webpack.config.js')

module.exports = merge(common, {
  plugins: [
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'production',
    }),
    new UglifyJsPlugin({
      cache: true,
    }),
  ],
})

最後筆者有將整個專案上傳到 GitHub ,有興趣的讀者歡迎點下面的連結上去參考。

react-webpack-example

總結

今天介紹了更進階一點的 React.js 開發環境的架設,終於把所有 React.js 的基本知識介紹完畢了,從明天開始的文章就會正式進入資料視覺化的介紹,如果有什麼問題歡迎在下方留言給我,沒問題的話明天要介紹用來進行資料視覺化的套件 D3.js 了。


上一篇
Day10-React環境架設(create-react-app)
下一篇
Day12-D3基本介紹(作用、svg)
系列文
React + D3 的正確姿勢30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言