Try   HackMD

Typescript ES6 + webpack 設定

必要 package

名稱 連結 用途
typescript link
webpack link
webpack-cli link
@webpack-cli/generators link webpack 環境設定範本
ts-loader link
npm install -D webpack webpack-cli @webpack-cli/generators typescript ts-loader

webpack v5 已經不需要額外安裝和設定 terser-webpack-plugin (用來壓縮發佈後的 js 內容)

設定

  • 建立 webpack 相關設定檔

    ​​​​npx webpack-cli init
    

    問答簡易選項

    ? Which of the following JS solutions do you want to use? Typescript

    ? Do you want to use webpack-dev-server? No

    ? Do you want to simplify the creation of HTML files for your bundle? No

    ? Which of the following CSS solutions do you want to use? none

    ? Do you like to install prettier to format generated configuration? Yes

    ? Overwrite package.json? overwrite

    ? Overwrite tsconfig.json? 檔案已存在才出現

    會產生 tsconfig.json, webpack.config.js, 複寫 package.json

  • 修改 webpack-cli 產生的 tsconfig.json

    ​​​​"target": "es6",
    ​​​​"module": "ESNEXT",
    ​​​​"moduleResolution": "node",
    ​​​​"esModuleInterop": true
    

    此欄位可移除, 或是修改成入口檔案

    ​​​​"files": ["src/index.ts"]
    
    延伸-測試 tsconfig include 欄位是否有作用
    1. root 資料夾新增檔案 abc.ts
    ​​​​export class ABC {}
    
    1. 在入口檔案 src/index.ts 建立 ABC 實體
    ​​​​import { ABC } from "../abc";
    ​​​​
    ​​​​export class Index{
    ​​​​    abc: ABC;
    ​​​​    constructor(){
    ​​​​        this.abc = new ABC();
    ​​​​    }
    ​​​​}
    
    
    • 測試1: 設定 include 指定資料夾 src, 測試放在外層的 abc.ts 能否正常讀取
    ​​​​"include": ["src"]
    
    ​​​​通過編譯, 不會出現找不到 abc.ts 的錯誤, runtime 也正常運作
    

    • 測試2: 移除 include 比對差異
    ​​​​通過編譯, runtime 正常運作
    

    官方文件指出在沒設定 files 和 include, 預設值是 ["**/*"] 會編譯專案目錄底下所有相關檔案 link

    • 測試3: include 指定一個不存在的資料夾 aaa
    ​​​​"include": ["aaa"]
    
    ​​​​無法通過編譯 ERROR
    ​​​​  TS18003: No inputs were found in config file 'tsconfig.json'. Specified 'include' paths were '["aaa"]' and 'exclude' paths were '[]'
    

    • 測試4: 建立 aaa 資料夾, 裡面無任何檔案
    ​​​​一樣出現 ERROR TS18003
    

    • 測試5: 在 aaa 資料夾內隨意新增一個 ts 檔, 並加上 class
    ​​​​通過編譯
    

    結論: tsconfig.json 即使不設定 include 資料夾, 也不影響 webpack 發佈

    tsconfig.json 範例
    ​​​​{
    ​​​​  "compilerOptions": {
    ​​​​    "allowSyntheticDefaultImports": true,
    ​​​​    "noImplicitAny": true,
    ​​​​    "module": "ESNEXT",
    ​​​​    "target": "es6",
    ​​​​    "allowJs": true
    ​​​​  }
    ​​​​}
    
  • 修改 webpack.config.js

    ​​​​entry: "./src/入口預設檔案.ts",
    ​​​​output: {
    ​​​​path: path.resolve(__dirname, "輸出資料夾"),
    ​​​​filename: "輸出檔名.js"
    ​​},
    
    webpack.config.js 範例
    ​​​​const path = require("path");
    ​​​​const isProduction = process.env.NODE_ENV == "production";
    
    ​​​​const config = {
    ​​​​  entry: "./src/index.ts",
    ​​​​  output: {
    ​​​​    path: path.resolve(__dirname, "output"),
    ​​​​    filename: "index.js"
    ​​​​  },
    ​​​​  plugins: [],
    ​​​​  module: {
    ​​​​    rules: [
    ​​​​      {
    ​​​​        test: /\.(ts|tsx)$/i,
    ​​​​        loader: "ts-loader",
    ​​​​        exclude: ["/node_modules/"],
    ​​​​      },
    ​​​​      {
    ​​​​        test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
    ​​​​        type: "asset",
    ​​​​      },
    ​​​​    ],
    ​​​​  },
    ​​​​  resolve: {
    ​​​​    extensions: [".tsx", ".ts", ".js"],
    ​​​​  },
    ​​​​};
    
    ​​​​module.exports = () => {
    ​​​​  if (isProduction) {
    ​​​​    config.mode = "production";
    ​​​​  } else {
    ​​​​    config.mode = "development";
    ​​​​  }
    ​​​​  return config;
    ​​​​};
    
  • 修改 package.json

    ​​​​"description": "My webpack project",
    ​​​​"name": "my-webpack-project"
    
    package.json 範例
    ​​​​{
    ​​​​  "devDependencies": {
    ​​​​    "@webpack-cli/generators": "^2.1.0",
    ​​​​    "prettier": "^2.3.0",
    ​​​​    "ts-loader": "^9.2.2",
    ​​​​    "typescript": "^4.3.2",
    ​​​​    "webpack": "^5.38.1",
    ​​​​    "webpack-cli": "^4.7.0"
    ​​​​  },
    ​​​​  "version": "1.0.0",
    ​​​​  "description": "My webpack project",
    ​​​​  "name": "my-webpack-project",
    ​​​​  "scripts": {
    ​​​​    "build": "webpack --mode=production --node-env=production",
    ​​​​    "build:dev": "webpack --mode=development",
    ​​​​    "build:prod": "webpack --mode=production --node-env=production",
    ​​​​    "watch": "webpack --watch"
    ​​​​  }
    ​​​​}
    

ES6 module

  • 假設 src 資料夾有 3 個 class, 其中入口是 Main
    ​​​​export class A {}
    
    ​​​​export class B {}
    
    ​​​​export class Main {}
    
  • 在未使用 webpack 之前
    匯入 module 需要含副檔名
    ​​​​import { A } from "./A.js";
    ​​​​import { B } from "./B.js";
    ​​​​
    ​​​​export class Main {
    ​​​​    a: A;
    ​​​​    b: B;
    ​​​​    
    ​​​​    constructor(){
    ​​​​        this.a = new A();
    ​​​​        this.b = new B();
    ​​​​    }
    ​​​​}
    
  • 導入 webpack 之後
    import module 不能加上副檔名, 否則會找不到
    ​​​​import { A } from "./A";
    ​​​​import { B } from "./B";
    ​​​​
    ​​​​export class Main {
    ​​​​    a: A;
    ​​​​    b: B;
    ​​​​    
    ​​​​    constructor(){
    ​​​​        this.a = new A();
    ​​​​        this.b = new B();
    ​​​​    }
    ​​​​}
    
  • 使用 VS Code 總是自動加上 module 副檔名的解決方法
    1. 開啟 Preference
    2. 搜尋 Import Module Specifier Ending
    3. 不要選 js, 選 auto

發佈

npm run build

選用 package

名稱 連結 用途
copy-webpack-plugin link 複製特定檔案到發佈資料夾
clean-webpack-plugin link 用來清空發佈資料夾
  • copy-webpack-plugin + clean-webpack-plugin

    webpack.config.js 簡易設定

    ​​​​const CopyPlugin = require('copy-webpack-plugin');
    ​​​​const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    ​​​​
    ​​​​const config = {
    ​​​​...​​​​plugins: [
    ​​​​    new HtmlWebpackPlugin({
    ​​​​      template: "index.html"
    ​​​​    }),
    ​​​​    new CopyPlugin({
    ​​​​      patterns: [{
    ​​​​        from: path.resolve(__dirname, "來源相對路徑"),
    ​​​​        to: path.resolve(__dirname, "目標相對路徑"),
    ​​​​      }]
    ​​​​    }),
    ​​​​    new CleanWebpackPlugin()
    ​​],
    ​​​​...略
    ​​​​}
    

    更多用法請參考文件 link

    錯誤排解

    HookWebpackError: Only file and data URLs are supported by the default ESM loader

    copy-webpack-plugin 版本不相容, 嘗試升級或降版本


導入SASS

需要安裝的 package

名稱 連結 用途
sass-loader link
node-sass link
css-loader link
mini-css-extract-plugin link 產生css

修改 webpack.config.js

​ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
​ ...
​ const config = {
​     plugins: [
​         new MiniCssExtractPlugin({
​         filename: '[name].css',
​       })
​     ],
​     module: {
​         rules: [
​             {
​               test: /\.s[ac]ss$/i,
​               use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
​             },
​         ]
​     }
​ }

在入口檔案 import scss

發佈的時候才會將 scss 編譯成 css

import "相對路徑/來源檔案.scss";

使用 jquery

  • 安裝
    ​​​​npm install --save-dev @types/jquery
    ​​​​npm install jquery --save
    
  • webpack 設定
    ​​​​plugins: [
    ​​​​    new webpack.ProvidePlugin({
    ​​​​        $: "jquery",
    ​​​​    }),
    ​​​​]
    

疑難排解

  • 每次都固定發佈成 main.css, 想更換檔名

    webpack entry 預設名稱是 main
    需要修改 webpack.config.js 的 entry 欄位

    ​​​​entry: "./src/index.ts"
    

    改成

    ​​​​entry: { entry自訂名稱: "./src/index.ts" }
    

參考文件


tags: Node.js