[ 前端工具 ] - Webpack


Posted by krebikshaw on 2020-08-28

Webpack 安裝懶人包 (置頂)

1. npm init -y
2. npm install webpack webpack-cli --save-dev
3. touch webpack.config.js
4. npm install jquery --save-dev
5. npm install -D babel-loader @babel/core @babel/preset-env
6. npm install sass-loader sass --save-dev
7. npm install --save-dev style-loader
8. npm install --save-dev css-loader
9. npm install --save-dev webpack-dev-server
10. npm install --save-dev html-webpack-plugin

如果要執行 React 不要忘記還有東西要裝

webpack.config.js 設定檔貼上下述程式碼:

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
  },
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ],
      }, {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
    })
  ],
};

package.json 中的 script 加上下列兩項設定:

"scripts": {
  "start": "webpack-dev-server --open",
  "build": "webpack",
},

// 直接在 CLI 下 npm run start 可以直接打開 dev server

在 src 資料夾下的 index.js 開頭加上:

import scss from './main.scss';
import $ from 'jquery';
  • 設定完成!
  • 必要設定:
    • 根目錄:
      • index.html
    • src:
      • index.js
      • main.scss
  • 利用 npm run start 可啟動 dev server

補充: 建置 React 環境

上述的 1,2,3,5 項 Webpack, babel 等功能要先安裝,另外還還需要裝幾樣東西:
1. npm install react react-dom --save-dev
2. npm install @babel/preset-react --save-dev

修改 webpack.config.js 底下 babel 的設定:

{
  presets: ['@babel/preset-env', '@babel/preset-react'],
}
  • React 官方提供的 create-react-app 安裝指令:
npm install -g create-react-app
create-react-app <app 名稱>

開始介紹 Webpack

背景

我們在電腦上將 A 檔案的程式,引入到 B 檔案來使用,可以透過 node 提供的 export, require 等方式來實現,這就是模組化的過程。
但是瀏覽器不支援這種 require 的形式,瀏覽器是透過全域變數去輸出 module,所以如果引入了不同的 library 它們用了相同的變數名稱,就會發生「衝突」。
所以我們要先了解,在瀏覽器與 Node 兩個不同的環境執行 JavaScript 處理模組化是不同的。Node 用的模組化規範是 CommonJS,而瀏覽器早期是沒有模組化規範的,一直到現今的瀏覽器,才出現了 ES Modules 這個原生的規範,但是由於這個規範很新(近幾年出現的),較舊的瀏覽器無法使用,所以才會出現了一些工具,讓瀏覽器可以利用類似引用檔案的方式來實現模組化

Webpack 就是可以幫你把模組包在一起,讓你可以在瀏覽器上實現模組的一個工具

簡介

Webpack 是你可以用 import 把資源加載進來,連圖片或是 css 也可以,因此也可以做到 compile css、轉換 JavaScript 等等

  • node.js 也辦不到 import 圖片 & CSS
  • webpack 把所有東西都視作一個資源

安裝

https://webpack.js.org/guides/getting-started/

  • npm init -y
  • npm install webpack webpack-cli --save-dev 安裝
  • 執行 npx webpack 就可以進行打包了

預設行為

  • 預設情況下,會把 src 這個資料夾底下的檔案,打包之後放到 dist 這個資料夾底下
  • 預設的設定會去 src 資料夾底下找 index.js 這個檔案設為入口點,打包後放到 dist 之後會改名成 main.js
  • 預設的情況,會在打包過程中將程式碼壓縮。

更改設定

  • 在根目錄底下建立 webpack.config.js 這個設定檔
  • 裡面寫上下述程式碼:
const path = require('path');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
  • entry:代表程式的入口點,預設會去找 src 資料夾底下的 index.js
    • 程式入口點的意思,就是要把其他 module 引入進來做事情的這個地方
  • filename:代表要輸出的檔案名稱,預設為 main.js
  • path代表輸出的路徑,__dirname 表示現在的資料夾,所以預設的輸出路徑為現在資料夾底下的 dist 這個資料夾
  • mode 預設為 production,代表為生產環境的版本,正式環境的版本,所以會將程式碼進行壓縮
    • 將 mode 改為 development,代表為開發模式的版本,這樣打包後,程式碼就不會被壓縮,比較能看得懂

在 package.json 中的 script 加上 "build" : "webpack"
就可以在 CLI 下 npm run build 這段指令來執行 webpack

  • webpack 執行後就會去找到 webpack.config.js 這個設定檔
  • 找到設定檔後,根據設定檔的內容打包

現代開發常會使用的 config 設定

Babel-loader
https://webpack.js.org/loaders/babel-loader/

  • npm install -D babel-loader @babel/core @babel/preset-env
  • webpack.config.js 檔案的 module 當中設定好 role
module: {
  rules: [
    {
      test: /\.m?js$/,  // test 代表什麼樣的檔案會被 load 進來,這邊是只要是 js 結尾或者 m js 結尾的檔案就會被 load 進來
      exclude: /(node_modules|bower_components)/,  // 不需要被轉換的檔案,因為 node_modules 原本就被轉換過了
      use: {
        loader: 'babel-loader', // 使用的 loader 為 babel-loader
        options: {     // options 是 babel 的轉換方式,可以直接寫在這裡,或者寫在 babelrc 裡面,這邊就不用寫了
          presets: ['@babel/preset-env'] 
        }
      }
    }
  ]
}

sass-loader
https://webpack.js.org/loaders/sass-loader/

  • npm install sass-loader sass --save-dev
  • webpack.config.js 檔案的 module 當中設定好 role
const path = require('path');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      // 加上這段
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      }, {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
          presets: ['@babel/preset-env'] 
        }
      }
    }
  ]
}

devServer

 const path = require('path');

 module.exports = {
   mode: 'production',
   entry: './src/index.js',
   output: {
     filename: 'main.js',
     path: path.resolve(__dirname, 'dist'),
   },
   // 加上這一段
   devServer: {
     contentBase: './dist',  // 最後編譯完的檔案要放哪裡
   },
   module: {
     rules: [
       {
         test: /\.s[ac]ss$/i,
         use: [
           'style-loader',
           'css-loader',
           'sass-loader',
         ],
       }, {
         test: /\.m?js$/,
         exclude: /(node_modules|bower_components)/,
         use: {
           loader: 'babel-loader',
           options: {
             presets: ['@babel/preset-env'] 
           }
         }
       }
     ]
   }
 }
  • 在 package.json 中的 script 加上 "start": "webpack-dev-server --open" 這段指令,就可以在 CLI 下 npm run start 這段指令把 devServer 打開

InlineSourceMap
https://webpack.js.org/guides/development/#using-source-maps

  • 可以在瀏覽器上 debug 的時候,直接顯示原始程式碼的長相,讓你更方便做 debug
  • webpack.config.js 加上 devtool: 'inline-source-map',
 const path = require('path');

 module.exports = {
   mode: 'production',
   entry: './src/index.js',
   output: {
     filename: 'main.js',
     path: path.resolve(__dirname, 'dist'),
   },
   // 加上這段
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist', 
   },
   module: {
     rules: [
       {
         test: /\.s[ac]ss$/i,
         use: [
           'style-loader',
           'css-loader',
           'sass-loader',
         ],
       }, {
         test: /\.m?js$/,
         exclude: /(node_modules|bower_components)/,
         use: {
           loader: 'babel-loader',
           options: {
             presets: ['@babel/preset-env'] 
           }
         }
       }
     ]
   }
 }

HtmlWebpackPlugin
https://webpack.js.org/plugins/html-webpack-plugin/#root

  • 在打包好 js 及 css 之後,可以動態自動幫你產生 html
  • npm install --save-dev html-webpack-plugin
  • webpack.config.js 設定檔開頭多一段 var HtmlWebpackPlugin = require('html-webpack-plugin');
  • webpack.config.js 設定檔結尾多一段 plugins: [new HtmlWebpackPlugin()]
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');

module.exports = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
  plugins: [new HtmlWebpackPlugin()]
};

gulp vs Webpack

gulp 是一個任務管理工具,他可以讓我們依照設計的劇本,去執行我們指定的 task(任務)

  • 例如:
    • 壓縮任務
    • babel
    • sass
    • 定時發 API
  • 這些任務可以同時進行或者按照順序進行
  • 但 gulp 本身不具備打包的功能 (除非引用 webpack 的 task)

Webpack 是一個打包各項模組的工具,只是在 bundle 的過程中,這些 loader 具備一些功能,順便幫我們達成我們想要的任務

  • webpack 可以藉由 loader 以及 plugin 做很多有趣的事,例如說:
    • 在載入 JS 的時候順便做 uglify
    • 在載入 CSS 的時候順便做 minify
    • 把打包出來的檔名順便加上 hash
    • 根據不同頁面打包不同的檔案,就不用一次載入全部 JS
    • 支援動態引入 JS,有需要的時候才載入
  • Webpack 藉由這些 loader 達成類似任務的動作
  • 但是 Webpack 本身不具備 task 的功能 (除非引用了 gulp 的 plugin)

參考文章

webpack 新手教學之淺談模組化與 snowpack


#Webpack







Related Posts

MTR04_0630

MTR04_0630

別猶豫了,來修 CS50 吧!

別猶豫了,來修 CS50 吧!

後端軟體工程工具箱:資料庫/SQL/ORM篇

後端軟體工程工具箱:資料庫/SQL/ORM篇


Comments