2021/02/01

Work With Typescript And Webpack And Route

呈上個文章,如果我們想有類似 SPA 那種 routes 的功能,讓重複資源如 jQuery 統一一包該怎麼實做。

目錄結構

|   a.html
|   b.html
|   tsconfig.json
|   webpack.config.js
+---app
|
\---src
    |   main.ts
    |   routes.ts
    \---class
            a.ts
            b.ts
            main.interface.ts

我把 index.ts 改成了 main.ts,增加了,程式碼內容如下:

a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Typescript + Webpack</title>
    <script src="app/main.js"></script>
</head>
<body id="a">
    <div id="content"></div>
</body>
</html>
b.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Typescript + Webpack</title>
    <script src="app/main.js"></script>
</head>
<body id="b">
    <div id="content"></div>
</body>
</html>
main.ts
import $ from 'jquery';
import { routes } from './routes';

$(function () {
    const classLoader = async (routeName: string): Promise<any> => {
        const imported = await import('./class/' + routeName);
        const className = routeName.toUpperCase();

        return new imported[className]();
    }

    routes.forEach(route => {
        if ($(`body#${route}`).is('*')) {
            classLoader(route).then(target => target.init());

            return false;
        }
    });
});
routes.ts
export const routes: string[] = [
    'a',
    'b'
]
webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        main: {import: './src/main.ts'}
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    output: {
        path: path.resolve(__dirname, 'app'),
    },
};
main.interface.ts
export interface mainInterface {
    init(): void
}
a.ts
import { mainInterface } from './main.interface';
import $ from 'jquery';

export class A implements mainInterface {
    init(): void {
        $('div#content').html('a');
    }
}
b.ts
import { mainInterface } from './main.interface';
import $ from 'jquery';

export class B implements mainInterface {
    init(): void {
        $('div#content').html('b');
    }
}

N.html 對應 N.ts,將所有要對應的 class 設定加到 routes.tsmain.ts 會動態偵測到 html 檔案的 body 有沒有相對應的 id,有的話就去撈相對應的 class,而相對應的 class 繼承 interface 一定要有 init() 這個 method,最為這個頁面時要做的預設事件,這樣 compile 的結果 jQuery 或其他的套件只會有一份,並且做到隔離不同頁面所需要的功能。

沒有留言: