2016年9月17日 星期六

typescript + SystemJS + npm + jQuery (Netbeans, Eclipse)

這篇主要紀錄在Netbeans和Eclipse中使用Typescript,並配合SystemJS的範例,再來我們要利用npm來安裝JQuery並用SystemJS引入JQuery模組,學習建立自己的javascript module。

這篇要實現的需求如下:
  1. 在Netbeans和Eclipse中使用typescript外掛編譯我們的ts檔成js檔。
  2. 使用npm安裝JQuery。
  3. 使用SystemJS引入JQuery模組並使用。
  4. 建立一個自製的JS module, Greeter,配製好相應的package.json和export設定,放到node_modules中。
  5. import自制的Greeter,並建立一個myGreeter去entend(繼承)Greeter擴充功能。
以下是我們完成的目錄結構,需注意到的是,藍色框線標示的js及map檔是ts檔被typescript編譯出來的檔案:



接下來講解步驟:

  1. 安裝npm(這邊直接安裝node.js)
    首先因為typescript外掛很多都是直接用到了node.js去實現,並且我們之後會練習使用npm來安裝JQuery,而node.js本身已有npm的功能,所我們先去node.js官網下載並安裝node.js。
    安裝完以後可以在命令列視窗打npm -v 來確認版本
  2. 在安裝Netbeans和Eclipse中安裝、使用、配置Typescript外掛
    1. Netbeans
      可以在Release頁下載最新版的typescript外掛,將nbm檔下載下來後,到netbeans的
      Tools --> plugins --> Downloaded --> Add Plugins... 選擇nbm檔案安裝即可。
    2. Eclipse
    3. 配置tsconfig.json
      tsconfig.json是typescript的設定檔(選用),它可以讓我們對typescrip進行許多設定配置,在這邊我們在專案的根目錄中建立一個tsconfig.json並撰寫內容如下:
      tsconfig.json
      {
        "compileOnSave": true,
        "compilerOptions": {
          "target": "es5",
          "module": "commonjs",
          "moduleResolution": "node",
          "sourceMap": true,
          "emitDecoratorMetadata": true,
          "experimentalDecorators": true,
          "removeComments": false,
          "noImplicitAny": false
        }
      }
      其中"compileOnSave"指的是在ts檔儲存時就會進行編譯,
      "sourceMap"指的是要不要產生map檔。
  3. 配置package.json
    package.json可以用來管理由npm安裝的module,當我們使用npm install XXX --save指令安裝js module時,可以順便將安裝的module資訊寫到package.json中。
    我們也可以用已經寫好module資訊的package.json,用npm install指令來一定安裝所需的module。
    在這邊我們先寫一個簡單的package.json就好:
    package.json:
  4. {
      "name": "Administrator",
      "dependencies": {
      }
    }
    
    其中dependencies指的就是已安裝的modules。
  5. 使用npm安裝JQuery及其定義檔
    拉下來我們要利用npm來安裝JQuery及其定義檔(給Typescript看的,有定義其介面),在命令列視窗到packge.json的地方打上npm install jquery --save,就會將JQuery的module安裝到 "node_modules" 資料夾中,並且也會將module的資訊寫到package.json的dependencies中。
    同樣的,JQuery的定義檔也可以用 npm install @types/jquery --save 安裝。
    可以看到在 "node_modules" 資料夾中的jquery和@types/jquery資料夾中也有相應的package.json,而其中有main這個屬性,標示著typescript要用其modules時,要import (或require)的對像。
  6. 使用System.js
    我們可以利用System.js (不只這個選擇) 來使用modules,模組化地組織我們的程式。
    在這裡我們寫一個systemjs.config.js來設定System.js載入modules時使用的規則。
    內容如下:
    systemjs.config.js
    (function (global) {
        System.defaultJSExtensions = true; //設定如果沒指定副檔名的話,預設是js
        System.config({
            paths: {
                '*': './node_modules/*',  //預設import的路徑指到node_modules/*資料夾
                                          //星號(*)不加會錯,加了代表相對路徑
                'js/*': 'js/*'            //js資料夾下的路徑導到js資料夾下
            },
            //設定packageConfigPaths,如果path是資料夾的話,會去尋找
            //資料夾中的package.json裡的main來得到正確的import路徑
            packageConfigPaths: ['./node_modules/*/package.json']
        });
    })(this);
  7. 自製的Greeter類別及配製
    現在來練習Typescript類別的寫法,等等要來練習繼承,這邊我們要寫的類別如下:node_modules/Greeter/src/Greeter.ts:
    export class Greeter {
        name: string;
        constructor(name: string = "NoName"){
            this.name = name;
        }
        greet(): void {
            console.log("Hello, " + this.name)
        }
    }
    可以看到Greeter類別有一個屬性name,其型別是string,建構子(constructor)接受一個string(可選,如果沒給會用預設值"NoName")。
    Greeter還有一個function屬性叫做greet(),沒有回傳值(void),只會在console.中印出 "Hello, " + this.name。
    並且撰寫它的package.json,指定main到Greeter.js:
    node_modules/Greeter/package.json:
    {
        "name": "Greeter",
        "main": "./src/Greeter.js"
    }
  8. 自製繼承Greeter的類別myGreeter
    再來撰寫自己的類別myGreeter,繼承Greeter,擴充一個function叫goodBye(),會印出"GoodBye, " + this.name,內容如下:
    js/myModules/myGreeter/myGreeter.ts:
    import { Greeter } from "Greeter";
    
    export class myGreeter extends Greeter{
        constructor(name?:string){
            super(name);
        }
        goodBye(): void {
            console.log("GoodBye, " + this.name)
        }
    }
  9. 測試
    接下來我們來寫一個html來測試JQuery和我們的Greeter、myGreeter能不能被正確地引用及使用。撰寫以下檔案:
    js/main.ts:
    //測試Greeter是否能成功被import及使用
    import { Greeter } from "Greeter";
    new Greeter().greet();
    
    //測試myGreeter是否能成功被import及使用
    import { myGreeter } from "./myModules/myGreeter/myGreeter";
    new myGreeter().goodBye();
    
    //測試JQuery是否能成功被import及使用
    import * as $ from "jquery";
    $("#jqueryTest").html("jquery loaded.");
    

    index.html:
    <!DOCTYPE html>
    <html>
        <head>
            <title>TODO supply a title</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            
            <script src="js/system.js"></script>
            <script src="systemjs.config.js"></script>
            <script>            
                //引用js/main.js
                System.import('js/main').catch(function(err){ console.error(err); });
            </script>
        </head>
        <body>
            <!-- 如可成功載入JQuery,會在main.js用JQuery將其文字換掉 -->
            <div id="jqueryTest">loading...jQuery</div>
        </body>
    </html>

    如果成功的話,就會把<div id="jqueryTest>內的文字換掉,變成jquery loaded,然後在console印出Hello, NoName和GoodBye, NoName,如下圖:


原始檔下載:
typescript_test.7z

參考資料:

  1. How to make TypeScript work with SystemJS? (issue with .js extension)
  2. An option to load modules from node_modules #767

沒有留言 :

張貼留言