顯示具有 webpack 標籤的文章。 顯示所有文章
顯示具有 webpack 標籤的文章。 顯示所有文章

2024年8月25日 星期日

Webpack 使用 Bebel 並用 @babel/preset-typescript 使用 typescript

記錄下在使用 Webpack 時,
如何使用 Bebel 並用 @babel/preset-typescript 的方式配合使用 Typescript 的功能

將 @babel/preset-typescript 設定在 babel-loader 的 presets 裡就好了。

package.json:

webpack.config.js:

{
  "name": "xxx-proejct",
  "scripts": {
    "deploy": "webpack"
  },
  "devDependencies": {
    "@babel/core": "7.18.10",
    "@babel/preset-env": "7.18.10",
    "@babel/preset-typescript": "^7.24.7",
    "babel-loader": "8.2.5",
    "css-loader": "5.0.1",
    "mini-css-extract-plugin": "1.3.3",
    "sass": "1.54.9",
    "sass-loader": "10.1.0",
    "style-loader": "3.3.1",
    "webpack": "5.74.0",
    "webpack-cli": "4.10.0"
  }
}

webpack.config.js:

var path = require('path');
var MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
    entry: {
        index_js: {
            import: "./src/app.js",
            filename: "js/index_bundle.js"
        }
    },
    output: {
        path: __dirname + "/dist"
    },
    watch: false,
    devtool : 'source-map',
    mode : "production",
    resolve : {
     extensions : ['.js', '.ts'],
     modules: [path.resolve(__dirname, '.'), 'node_modules']
    },
    module: {
        rules : [{
            test : /\.(ts|js)$/,
            use : {
                loader : 'babel-loader',
                options : {
                    presets : ['@babel/preset-env', '@babel/preset-typescript']
                }
            }
        },
        {
          test: /\.s[ac]ss$/,
          use: [        
               MiniCssExtractPlugin.loader,
               "css-loader", "sass-loader"
              ]
        }]
    },
    plugins: [new MiniCssExtractPlugin({
        filename: "./css/index_bundle.css"
    })],
    externals: {
        angular: "angular"
    }
}

2020年12月31日 星期四

React 練習 - 使用 css, scss, img loader, image 壓縮

自己寫的 React, Webpack 練習,

練習了以下 webpack loader:


sass-loader : 

用來處理編譯 sass 檔案。


css-loader : 

用來處理 css 檔案。


style-loader : 

用來將 css 寫進網頁中 (不用在網頁中另寫 <link rel="stylesheet" href="xxx.css" />)。


image-webpack-loader : 

用來處理圖片檔案,有圖片壓縮等功能。


url-loader :

用來將圖片的 url 寫進網頁中,內部使用了 file-loader,所以可使用 file-loader 的選項參數,

有能把圖片的 url 轉成 base64 url 的等功能。


mini-css-extract-plugin : 

用來把處理好的 css 輸出成最後版本 css 檔案的功能,

網頁要使用 css 需自行加入 css style include, Ex:

<link rel="stylesheet" href="xxx.css" />)


實作了一個簡易的 tab 選單當範例來練習:

1. 有三個選單 tab,分別對應三個內容 (暫稱 content),內容中有各自的文字及各放置了不同的圖片。

2. 當滑鼠滑入 tab 中時  (mouseenter) ,下方會切換到對應的 Content。

檔案結構如下圖所示:


重要的程式碼如下 (以下根目錄以從 package.json 檔所在位置,也就是 WebContent 資料夾算起):

/index.html :
<!DOCTYPE html>
<html>
    <head>
        
    </head>
    <body>
        <div id="root"></div>
        <script src="dist/js/index_bundle.js"></script>
    </body>
</html>
/dev/js/index.jsx :
import React from "react"
import ReactDOM from "react-dom"
import {Main} from "./components/Main.jsx"

import "@projectDirPath/dev/css/style.scss"

ReactDOM.render(<Main/>, document.getElementById("root"));
/dev/js/components/Main.jsx :
import React from "react"
import {Tab} from "./Tab.jsx"
import {Content} from "./Content.jsx"
import dogImgSrc from "@projectDirPath/dev/img/dog.jpg"
import catImgSrc from "@projectDirPath/dev/img/cat.jpg"
import bananaCatImgSrc from "@projectDirPath/dev/img/bananaCat.jpg"

function Main(){
    const [itemList, setItemList] = React.useState([
                                                        {
                                                            title: "title1",
                                                            desc: "desc1",
                                                            img: dogImgSrc,
                                                            isActive: true
                                                        },
                                                        {
                                                            title: "title2",
                                                            desc: "desc2",
                                                            img: catImgSrc,
                                                            isActive: false
                                                        },
                                                        {
                                                            title: "title3",
                                                            desc: "desc3",
                                                            img: bananaCatImgSrc,
                                                            isActive: false
                                                        }
                                                    ]);

    function setItemActive(index){
        var updatedItemList = itemList.map((item, i) => {
            item.isActive = (i == index);
            return item;
        });

        setItemList(updatedItemList);
    }

    return (
        <React.Fragment>
            <div className="tab">
                {
                    itemList.map((item, index) => {
                        return <Tab item={item} key={index} index={index} setItemActive={setItemActive}/>;
                    })
                }
            </div>
            <div className="content">
                {
                    itemList.map((item, index) => {
                        return <Content item={item} key={index}/>;
                    })
                }
            </div>
        </React.Fragment>
    )
}

export {Main}
/dev/js/components/Content.jsx :
import React from "react"

function Content({item}){
    return (
        <div className={item.isActive ? "active" : ""}>{item.desc}<img src={item.img}/></div>
    );
}

export {Content}
/dev/js/components/Tab.jsx :
import React from "react"

function Tab({item, index, setItemActive}){

    function handleMouseEnter(){
        setItemActive(index);
    }

    return (
        <div className={item.isActive ? "active" : ""} onMouseEnter={handleMouseEnter}>{item.title}</div>
    );
}

export {Tab}
/dev/css/style.scss :
.tab {
    div {
        display: inline-block;
        width: 30%;
        height: 100px;
        background-color: green;
        background-color: yellow;
        border-bottom: 3px solid black;
    }

    div.active {
        background-color: yellow;
        border-left: 3px solid black;
        border-right: 3px solid black;
        border-top: 3px solid black;
        border-bottom: 3px solid yellow;
    }
}
  
.content {
    background-color: yellow;
    border-left: 3px solid black;
    border-right: 3px solid black;
    border-bottom: 3px solid black;

    div {
        display: none;
        padding: 3px;
    }

    div.active {
        display: block;
    }

    img {
        width : 30%;
    }
 }


webpack.config.js:

  var path = require('path');
//const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
 entry : "./dev/js/index.jsx",
 output : {
  path : path.resolve(__dirname, "dist"),
  filename : "js/index_bundle.js",
  publicPath : "dist/"
 },
 resolve: {
    alias: {
        '@projectDirPath': __dirname
    }
},
 watch : false,
 devtool : 'source-map',
 mode : "development", //"production",
 module : {
  rules : [ {
   test : /\.jsx?$/,
   use : {
    loader : 'babel-loader',
    options : {
     presets : [ '@babel/preset-react', '@babel/preset-env' ]
    }
   }
  },
  {
    test: /\.(png|jpg|gif|jpe?g|svg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 50 * 1024,
          outputPath: "img"
        }        
      },
      "image-webpack-loader"      
    ]
  },/*
  {
      test : /\.css$/,
      use : ["style-loader", "css-loader"]
  },*/
  {
    test: /\.s[ac]ss$/,
    use: [        
         "style-loader", //MiniCssExtractPlugin.loader,
         "css-loader", "sass-loader"
        ]
  }]
 }
 //, plugins: [new MiniCssExtractPlugin()]
}
  

package.json

  {
  "name": "reacttest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "runServer": "lite-server"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.7.5",
    "@babel/preset-env": "^7.7.5",
    "@babel/preset-react": "^7.7.4",
    "babel-loader": "^8.0.6",
    "css-loader": "^5.0.1",
    "file-loader": "^6.2.0",
    "image-webpack-loader": "^7.0.1",
    "lite-server": "^2.6.1",
    "mini-css-extract-plugin": "^1.3.3",
    "node-sass": "^5.0.0",
    "sass-loader": "^10.1.0",
    "style-loader": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  },
  "dependencies": {
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "^7.2.2",
    "redux": "^4.0.5"
  }
}

  

原始碼分享下載:

ReactTest2.7z


參考:

  1. Webpack 4 筆記 (3)
  2. 新手向 Webpack 完全攻略 (7) – 編譯圖片?略懂略懂
  3. Webpack 前端打包工具 - 使用 image-webpack-loader 壓縮圖片
  4. Webpack 前端打包工具 - 使用 sass-loader 編譯 Sass/SCSS 預處理器
  5. Webpack 前端打包工具 - 使用 mini-css-extract-plugin 把 CSS 抽離出來
  6. NPM – Webpack – 使用 import 的絕對路徑方法

2019年12月7日 星期六

React 練習 - ToDo List (待辦事項) 簡易實作

這篇要來記錄一下 React 的
ToDo List (待辦事項) 簡易實作(無用到 Redux 之類的)

首先先來看一下成果的樣子:

並將它分

接下來是需求說明:
  1. 有一個供使用者輸入的<input type="text"/> 框,使用者輸入待辦事項的文字後,
    按下Enter鍵(配合 <form>)或按下 "addToDo" 按鈕,可以加進下方的待辦事項顯示區域 (<ul><li>)。
    為了演示一下雙向資料流的實作,放了兩個待辦事項輸入框,
    在使用者在其中一個輸入框輸入資料時,另一個的輸入框會同步顯示輸入的待辦事項的內容。
  2. 使用者在輸入待辦事項的文字時,下方有一行文字可以顯示使用者正在輸入的文字。
  3. 下方的待辦事項清單中,各個待辦事項右方有一個 "Delete" 按鈕,按下可將待辦事項移除

再來把其需求分解成各個Component,如下圖所示:
  1. Main.jsx :
    統整所有 Component 的最上層 Component,也管理著 state。
  2. TextInput.jsx :
    供使用者輸入待辦事項的地方。
  3. TextDisplayer.jsx :
    顯示使用者正在輸入的待辦事項。
  4. ToDoList.jsx :
    顯示待辦事項例表的 Component,其內部用到了子 Component, "ToDoRow.jsx"。
  5. ToDoRow.jsx :
    顯示各個獨立待辦事項的 Component,包含著 Delete 等功能。

2019年7月18日 星期四

Typescript + Webpack (使用 ts-loader ) 練習

在"Typescript + Webpack (or SystemJs) 練習"這篇文章中,使用了多次指令分別去:
1. 用 npm 去 install 要的工具
2. 用 tsc 去使用 typescript 編譯
3. 用 webpack 去使用 webpack 打包程式

這次要來紀錄只使用 npm 指令,
因為 npm 的 package.json 可以設定 script 來方便的執行 command line 的指令,
而 webpack 可以用各種 loader 來處理項任務,其中 ts-loader 可以處理 typescript 的任務,
所以我們可以讓npm 去呼叫 webpack ,webpack 去呼叫 typescript 去完成任務。

這次的檔案結構跟上次差不多,如下所示:

其中,js 資料夾裡的檔案是 webpack 搭配 ts-loader 編擇 src資料夾下檔案所產生出來的,
package-lock.json不用管它,因為是npm 自已產生的。

我們先看看 Greeter.ts 和 test.ts :
Greeter.ts :
export class Greeter{
    name : string;
    constructor(name :string){
        this.name = name;
    }
    greet(){
        console.log("Hello, HIHI, " + this.name);
        alert("Hello, HIHI, " + this.name);
    }
}

test.ts :
import {Greeter} from "./Greeter";
 
let name : string = "Hugo";
let greeter : Greeter = new Greeter(name);
greeter.greet();

可以注意的是,在 test.ts 中 import 的Greeter可以只有檔名而沒有副檔名,因為在webpack.config.js中,有設定resolve {extensions : ['.js', '.ts']} 的設定。
接著我們來看看 npm的package.json、tyscript的tsconfig.json和webpack的webpack.config.js
三個 config 檔的內容:


package.json :
{
  "name": "webpacktypescripttest",
  "scripts": {
    "devEnvBuild": "npm install --save-dev typescript ts-loader webpack webpack-cli",
    "deploy": "webpack"
  },
  "devDependencies": {
    "ts-loader": "^6.0.4",
    "typescript": "^3.5.3",
    "webpack": "^4.36.1",
    "webpack-cli": "^3.3.6"
  }
}

tsconfig.json :
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    // "outDir": "./dist", //不需要
    "strict": true,
    "esModuleInterop": true    
  }
}

webpack.config.js :
var path = require('path');
module.exports = {
    entry: "./src/test.ts",
    output: {
        path: __dirname + "/js",
        filename: "test.js"
    },
    watch: false,
    devtool : 'source-map',
    mode : "production",
    resolve : {
     extensions : ['.js', '.ts']
    },
    module: {
     rules: [
       { 
        test: /\.ts$/, 
        use: 'ts-loader',
        include: path.resolve(__dirname, 'src')
       }
     ]
 }
}

可以注意到,在 tsconfig.json 中,我們不需要寫 outDir 來指定 typescript 的輸出位置,
其實就算指定了,經過 webpack 用 ts-loader 來執行 typescript 時,
也不會在 outDir 指的地方出現輸出的檔案。

先假設整個環境除了 npm 以外都沒建置完成,即 webpack, typescript, ts-loader.... 等
先用 command line 視窗到 webpackTypescriptTest 資料夾的路徑,
執行指令:
npm run devEnvBuild
就可以執行已經寫在 package.json 中,script 裡,devEnvBuild的指令,等同於執行
npm install --save-dev typescript ts-loader webpack webpack-cli
接著再執行
npm run deploy
就可以發現在 js 資料夾中,檔案被產生出來了,其中已經包括了 typescript的編擇和 webpack 的打包
可以注意到的是,在 webpack.config.js 中 ,
我們用了 module 設定了 ts-loader 來為 ts 檔在打包前進行了 typescript 的編譯。

最後我們在 index.html 中就可以使用 src/test.js 了 :

index.html :

 <head>
  <script src="js/test.js"></script>
 </head>
 <body> 
 </body>
</html>

原始碼下載:
webpackTypescriptTest.7z

參考資料:
  1.  TypeScript | webpack
  2. TYPESCRIPT合成WEBPACK中

2017年5月21日 星期日

Typescript + Webpack (or SystemJs) 練習

今天要來練習使用Typescript編寫Javascript,順便紀錄下如果JS Module的使用方式。

Typescript可以讓我們編寫的 ts 檔編譯成 js 檔,而如果有在 ts 檔裡撰寫Module的語法,
例如export, import等語句,Typescript可以依我們指定的module spec 來將 ts 檔編譯成不同
寫法的 js 檔,而可提供的有例如 amd, system, commonjs 等。

這裡會練習以下項目;

模組化 JS 執行工具:
SystemJs是一個可以執行JS Module的工具,
支援許多module spec,目前有
esm (ECMAScript Module),
cjs (CommonJS),
amd (Asynchronous Module Definition),
global (Global shim module format),
system (System.register or System.registerDynamic compatibility module format),
可以使用在node.js及Web應用中,在Web應用中,
可以在頁面上真接用 <script src="XXX/system.js"></script> 引入,
然後直接寫Javascript code 並指定程式進入點即可。

Webpack是一個功能強大的模組化打包工具,可以將多個資源(JS, CSS, images...)打包成一個檔案,可以解析例如commonjs的module spec,主要以命令列的方式使用,也可搭配其他外掛使用。

在這邊我們會先練習利用Typescript編譯 ts 檔,並且練習兩種不同的 module spec ,
system 和 commonjs, Typescript 對不同的 module spec 編譯出不同的 js 檔,
然後
system 我們會利用 SystemJs 來執行模組化的 js。
commonjs 我們會利用 Webpack 來打包編譯好的 js 檔成一個可執行的模組化 js。

Typescript IDE :
在這邊,可以準備一個有 Typescript 功能的 IDE,例如在這邊我使用 Visual Studio Code ,它有不錯的 Typescript 提供檢查功能及許多外掛,並且本身乾淨可以當一般的編輯器使用,當然也可以根據開發環境使用想應的工具外掛,例如 Netbeans 及 Eclipse (可以參考"Angular2簡易安裝使用 - Eclipse + Typescript plugin + System.js") 也有人提供Typescript外掛,享受使用 Typescript 的好處。
** Note **
Visual Studio Code 如果看不到JS、Typescript的提示文字,可以用"系統管理員"的方式開啟,應該就會出來了。

Typescript 的編譯:
在這邊為了了解最源頭的運作,我選擇使用最單純的方式,用 npm 安裝了 Typescript 後,直接用 tsc 指令配合 tsconfig.json 來執行編譯,許多開發環境的外掛,例如 Visual Studio Code 自己就有編譯Typescript的能力,不過其實最底層也都基本是呼叫 tsc 指令來完成工作。

簡易Server:
這邊使用了 lite-server 來在專案當下目錄建立簡易Server,因為Module JS的寫法會用到Ajax的呼叫,所以需要建立Server,當然要用其他例如webpack-dev-server、Netbeans, Eclipse 配合 Tomcat 之類的也是OK。

=========================================

首先,請先安裝 node.js (自動有 npm),
在全局安裝 Typescript、Webpack
npm install typescript -g
npm install webpack -g