Add CI & Deno Supported & Fix a lot of bugs & Webpack for building package

This commit is contained in:
186526 2022-07-02 17:01:00 +00:00 committed by GitHub
parent b3552cb6a2
commit 057c9b9cb5
25 changed files with 2035 additions and 86 deletions

14
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,14 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node packages
# RUN su node -c "npm install -g <your-package-list -here>"

View File

@ -0,0 +1,17 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
# Install tslint, typescript. eslint is installed by javascript image
ARG NODE_MODULES="tslint-to-eslint-config typescript"
COPY library-scripts/meta.env /usr/local/etc/vscode-dev-containers
RUN su node -c "umask 0002 && npm install -g ${NODE_MODULES}" \
&& npm cache clean --force > /dev/null 2>&1
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"

View File

@ -0,0 +1,39 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/typescript-node
{
"name": "Node.js & TypeScript",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local on arm64/Apple Silicon.
"args": {
"VARIANT": "16-bullseye"
}
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-next",
"oderwat.indent-rainbow",
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "yarn install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
"git": "latest"
}
}

22
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: yarn install
- name: Test handlers.js
run: yarn test

View File

@ -1,3 +1,5 @@
{ {
"compile-hero.disable-compile-files-on-did-save-code": false "compile-hero.disable-compile-files-on-did-save-code": true,
"deno.enable": false,
"editor.formatOnSave": true,
} }

View File

@ -4,7 +4,6 @@ import {
handler, handler,
route, route,
response, response,
ChainInterrupted,
} from "../index"; } from "../index";
import errorHandler from "./errorHandler"; import errorHandler from "./errorHandler";
@ -25,10 +24,18 @@ App.binding(
App.create( App.create(
"ANY", "ANY",
(): Promise<string> => (): Promise<string> =>
new Promise((resolve) => { new Promise(() => {
console.log("Hello World!"); console.log("Hello World!");
resolve("Hello World!"); throw new response("Hello World!");
throw ChainInterrupted; })
)
).binding(
"/(.*)",
App.create(
"ANY",
(): Promise<string> =>
new Promise((resolve) => {
resolve("Hello World?")
}) })
) )
); );

View File

@ -6,7 +6,6 @@ export { router } from "./src/router";
export { methodENUM as method } from "./src/interface/method"; export { methodENUM as method } from "./src/interface/method";
export { response } from "./src/interface/response"; export { response } from "./src/interface/response";
export { request } from "./src/interface/request"; export { request } from "./src/interface/request";
export { ChainInterrupted } from "./src/interface/index";
export * as platformAdapater from "./src/platform/export"; export * as platformAdapater from "./src/platform/export";
export { rootRouter }; export { rootRouter };

6
jest.config.js Normal file
View File

@ -0,0 +1,6 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
export default {
preset: 'ts-jest',
testEnvironment: 'node',
forceExit: true
};

View File

@ -20,22 +20,35 @@
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^3.13.0", "@cloudflare/workers-types": "^3.13.0",
"@types/jest": "^28.1.4",
"@types/node": "^18.0.0", "@types/node": "^18.0.0",
"@webpack-cli/generators": "^2.5.0", "@webpack-cli/generators": "^2.5.0",
"axios": "^0.27.2",
"jest": "^28.1.2",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"ts-jest": "^28.0.5",
"ts-loader": "^9.3.1", "ts-loader": "^9.3.1",
"ts-node": "^10.8.1",
"typescript": "^4.7.4", "typescript": "^4.7.4",
"webpack": "^5.73.0", "webpack": "^5.73.0",
"webpack-cli": "^4.10.0" "webpack-cli": "^4.10.0"
}, },
"sideEffects": false, "sideEffects": false,
"scripts": { "scripts": {
"build": "yarn build:node && yarn build:webworker", "build": "yarn clean && yarn build:node && yarn build:serviceworker && yarn build:cfworker && yarn build:deno",
"build:node": "TARGET=node webpack", "build:node": "BUILD_TARGET=node webpack",
"build:webworker": "TARGET=webworker webpack", "build:serviceworker": "BUILD_TARGET=serviceworker webpack",
"watch": "webpack --watch" "build:cfworker": "BUILD_TARGET=cfworker webpack",
"build:deno": "BUILD_TARGET=deno webpack",
"watch": "webpack --watch",
"clean": "rm -rf ./dist",
"demo": "env NODE_ENV=development yarn build:node && node ./dist/main.node.js",
"tsc": "tsc",
"test": "jest",
"coverage": "jest --collectCoverage --"
}, },
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
} },
"type": "module"
} }

View File

@ -1 +0,0 @@
console.log("Hello World!");

View File

@ -3,6 +3,5 @@ export { response } from "./response";
export { method } from "./method"; export { method } from "./method";
export { headers } from "./headers"; export { headers } from "./headers";
export { responder } from "./responder"; export { responder } from "./responder";
export const ChainInterrupted = new Error("ChainInterrupted");
export const AllMismatchInterrupted = new Error("AllMismatchInterrupted"); export const AllMismatchInterrupted = new Error("AllMismatchInterrupted");
export type path = string | RegExp; export type path = string | RegExp;

View File

@ -56,6 +56,6 @@ export enum methodENUM {
ANY = "ANY", ANY = "ANY",
} }
export type method = methodENUM | string; export type method = "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | "ANY" | methodENUM;
export default method; export default method;

View File

@ -4,17 +4,23 @@ export const platform = (() => {
if (typeof process != "undefined") { if (typeof process != "undefined") {
return "Node.js"; return "Node.js";
} }
if (typeof self != "undefined") { if (typeof Deno != "undefined") {
return "Web Worker"; return "Deno";
} }
if (typeof self != "undefined") {
return "Unknown"; return "Service Worker";
}
return undefined;
})(); })();
export const version = (() => { export const version = (() => {
switch (platform) { switch (platform) {
case "Node.js": case "Node.js":
return process.version; return process.version;
case "Deno":
return Deno.version.deno;
case "Service Worker":
return undefined;
default: default:
return "Unknown"; return undefined;
} }
})(); })();

67
src/platform/deno.ts Normal file
View File

@ -0,0 +1,67 @@
import { SWPlatformAdapter } from "./serviceworker";
import { platformAdapater } from "./index";
import { request } from "../interface/request";
import { headers } from "../interface/headers";
import { methodENUM } from "src/interface/method";
const DefaultConn: Deno.Conn = {
localAddr: {
transport: "tcp",
hostname: "0.0.0.0",
port: 80,
},
remoteAddr: {
transport: "tcp",
hostname: "0.0.0.0",
port: 80,
},
rid: 0,
closeWrite: async () => undefined,
readable: "",
writable: "",
read: async (p: Uint8Array) => null,
write: async (p: Uint8Array) => 0,
close: () => undefined,
};
export class DenoPlatformAdapter<T = any, K = any>
extends SWPlatformAdapter<T, K>
implements platformAdapater<T, K>
{
async listen(port: number): Promise<void> {
const Server: Deno.Listener = Deno.listen({ port });
for await (const connection of Server) {
const httpConnection = Deno.serveHttp(connection);
for await (const requestEvent of httpConnection) {
requestEvent.respondWith(this.handler(requestEvent, connection));
}
}
}
async handleRequest(nativeRequest: Request, connection: Deno.Conn = DefaultConn): Promise<request<T>> {
const requestHeaders = new headers(
Object.fromEntries(nativeRequest.headers.entries())
);
const requestMessage: request<T> = new request(
<methodENUM>nativeRequest.method,
new URL(nativeRequest.url),
requestHeaders,
await nativeRequest.text(),
{},
`${connection.remoteAddr.hostname}:${connection.remoteAddr.port}` || ""
);
return requestMessage;
}
async handler(event: FetchEvent, connection: Deno.Conn = DefaultConn): Promise<Response> {
return await this.handleResponse(
await this.handleRequest(event.request, connection).then((request) =>
this.router.respond(request)
)
)
}
}

View File

@ -1,9 +1,11 @@
import { NodePlatformAdapter } from "./node"; import { NodePlatformAdapter } from "./node";
import { SWPlatformAdapter } from "./serviceworker"; import { SWPlatformAdapter } from "./serviceworker";
import { DenoPlatformAdapter } from "./deno";
export const platformAdapaterMapping = { export const platformAdapaterMapping = {
"Node.js": NodePlatformAdapter, "Node.js": NodePlatformAdapter,
"Web Worker": SWPlatformAdapter, "Service Worker": SWPlatformAdapter,
"Deno": DenoPlatformAdapter,
}; };
export { NodePlatformAdapter, SWPlatformAdapter }; export { NodePlatformAdapter, SWPlatformAdapter, DenoPlatformAdapter };

View File

@ -1,5 +1,5 @@
import { request, response } from "../interface"; import { request, response } from "../interface/index";
import { router } from "../../index"; import { router } from "../router";
export interface platformAdapater<T = any, K = any> { export interface platformAdapater<T = any, K = any> {
router: router<T, K>; router: router<T, K>;

View File

@ -1,9 +1,10 @@
import { platformAdapater } from "./index"; import { platformAdapater } from "./index";
import { request, response } from "../interface"; import { request, response } from "../interface/index";
import { router } from "../router"; import { router } from "../router";
import { headers } from "../interface/headers"; import { headers } from "../interface/headers";
import http from "http"; import http from "http";
import { methodENUM } from "src/interface/method";
export class NodePlatformAdapter<T = any, K = any> implements platformAdapater { export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
public router: router<T, K>; public router: router<T, K>;
@ -38,7 +39,7 @@ export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
} }
let body: string = ""; let body: string = "";
const ip: string = nativeRequest.socket.remoteAddress?.replace("::ffff:","") ?? "0.0.0.0"; const ip: string = nativeRequest.socket.remoteAddress?.replace("::ffff:", "") ?? "0.0.0.0";
const requestHeaders = new headers(<any>nativeRequest.headers); const requestHeaders = new headers(<any>nativeRequest.headers);
if (!["GET", "HEAD", "DELETE", "OPTIONS"].includes(nativeRequest.method)) { if (!["GET", "HEAD", "DELETE", "OPTIONS"].includes(nativeRequest.method)) {
@ -54,7 +55,7 @@ export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
} }
return new request<T>( return new request<T>(
nativeRequest.method, <methodENUM>nativeRequest.method,
new URL( new URL(
nativeRequest.url, nativeRequest.url,
`http://${requestHeaders.get("host") ?? "localhost"}` `http://${requestHeaders.get("host") ?? "localhost"}`

View File

@ -4,6 +4,8 @@ import { response } from "../interface/response";
import { router } from "../router"; import { router } from "../router";
import { headers } from "../interface/headers"; import { headers } from "../interface/headers";
import { methodENUM } from "src/interface/method";
export class SWPlatformAdapter<T = any, K = any> implements platformAdapater { export class SWPlatformAdapter<T = any, K = any> implements platformAdapater {
public router: router<T, K>; public router: router<T, K>;
@ -22,7 +24,7 @@ export class SWPlatformAdapter<T = any, K = any> implements platformAdapater {
Object.fromEntries(nativeRequest.headers.entries()) Object.fromEntries(nativeRequest.headers.entries())
); );
const requestMessage: request<T> = new request( const requestMessage: request<T> = new request(
nativeRequest.method, <methodENUM>nativeRequest.method,
new URL(nativeRequest.url), new URL(nativeRequest.url),
requestHeaders, requestHeaders,
await nativeRequest.text(), await nativeRequest.text(),

View File

@ -3,7 +3,6 @@ import {
path, path,
response, response,
request, request,
ChainInterrupted,
AllMismatchInterrupted, AllMismatchInterrupted,
responder, responder,
method, method,
@ -132,8 +131,8 @@ export class router<K = any, V = any> {
throw AllMismatchInterrupted; throw AllMismatchInterrupted;
} }
} catch (e) { } catch (e) {
if (e === ChainInterrupted) { if (e instanceof response) {
return e.response; throw e;
} }
if (e === AllMismatchInterrupted) mismatchCount++; if (e === AllMismatchInterrupted) mismatchCount++;
else { else {
@ -183,16 +182,16 @@ export class rootRouter<K = any, V = any> extends router<K, V> {
public adapater: platformAdapater<K, V>; public adapater: platformAdapater<K, V>;
errorResponder = errorResponder =
(errorCode: number, errorMessage?: string) => (errorCode: number, errorMessage?: string) =>
async (_request: request<K>): Promise<response<V>> => async (_request: request<K>): Promise<response<V>> =>
new response(errorMessage ?? "", errorCode); new response(errorMessage ?? "", errorCode);
respond = async (request: request<K>): Promise<response<V>> => { respond = async (request: request<K>): Promise<response<V>> => {
let responseMessage: response<V> = new response(""); let responseMessage: response<V> = new response("");
try { try {
responseMessage = await this._respond(request, responseMessage); responseMessage = await this._respond(request, responseMessage);
} catch (e) { } catch (e) {
if (e === ChainInterrupted) { if (e instanceof response) {
return responseMessage; return e;
} else if (e === AllMismatchInterrupted) { } else if (e === AllMismatchInterrupted) {
responseMessage = responseMessage =
(await this.errorResponder(404, "404 Not Found\n")(request)) ?? (await this.errorResponder(404, "404 Not Found\n")(request)) ??
@ -214,7 +213,8 @@ export class rootRouter<K = any, V = any> extends router<K, V> {
useMappingAdapter( useMappingAdapter(
mapping: { [platform: string]: platformAdapaterConstructor } = platformAdapaterMapping mapping: { [platform: string]: platformAdapaterConstructor } = platformAdapaterMapping
): this { ): this {
if(mapping[platform] == undefined) throw new Error("Platform not found in mapping"); if (typeof platform == "undefined") throw new Error("Cannot detect platform");
if (mapping[platform] == undefined) throw new Error("Platform not found in mapping");
else this.useAdapater(mapping[platform]); else this.useAdapater(mapping[platform]);
return this; return this;
} }

60
test/node.test.ts Normal file
View File

@ -0,0 +1,60 @@
import _ from "./test-server";
import Axios from "axios";
_.listen(3000);
const Instance = Axios.create({
baseURL: "http://localhost:3000"
})
const randomString = () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
describe("Test server", () => {
test("normal 200 response", async () => {
expect.assertions(2);
const { data, status } = await Instance.get("/");
expect(status).toEqual(200);
expect(data).toEqual("200 OK");
})
test("post response", async () => {
expect.assertions(2);
const string = randomString();
const { data, status } = await Instance.post("/post", string);
expect(status).toEqual(200);
expect(data).toEqual(string);
})
test("change header and status code", async () => {
expect.assertions(3);
const { data, status, headers } = await Instance.get("/header");
expect(status).toEqual(204);
expect(headers["itis"]).toEqual("work");
expect(data).toEqual("");
})
test("get param", async () => {
expect.assertions(2);
const string = randomString();
const { data, status } = await Instance.get(`/info/${string}`);
expect(status).toEqual(200);
expect(data).toEqual(string);
})
test("chain interrupted", async () => {
expect.assertions(2);
const { data, status } = await Instance.get(`/info/foo`);
expect(status).toEqual(200);
expect(data).toEqual("hit");
})
})

25
test/test-server.ts Normal file
View File

@ -0,0 +1,25 @@
import * as handlersJS from '../index';
const App = new handlersJS.rootRouter();
App.binding("/", App.create("GET", async () => "200 OK"));
App.binding("/post", App.create("POST", async (request: handlersJS.request<any>) => request.body));
App.binding("/header", App.create("GET", async () => {
const response = new handlersJS.response<any>("");
response.status = 204;
response.headers.set("itis", "work");
return response;
}));
App
.route("/info/(.*)")
.binding("/foo", App.create("GET", (): Promise<handlersJS.response<any>> => new Promise(resolve => {
throw new handlersJS.response("hit")
})))
.binding("/(.*)", App.create("GET", async (request: handlersJS.request<any>) => request.params[0] ?? "not found"));
App.useMappingAdapter();
export default App;

View File

@ -1,14 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "esnext", "target": "esnext",
"module": "commonjs", "module": "esnext",
"lib": [ "lib": ["ESNext"],
"ESNext", "types": ["@cloudflare/workers-types", "@types/node", "@types/jest"],
],
"types": [
"@cloudflare/workers-types",
"@types/node",
],
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"outDir": "./dist", "outDir": "./dist",
@ -28,18 +23,12 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"baseUrl": ".", "baseUrl": ".",
"plugins": [ "plugins": [{
{ "transform": "@zerollup/ts-transform-paths"
"transform": "@zerollup/ts-transform-paths", }],
} "declaration": true
],
}, },
"exclude": [ "exclude": ["node_modules"],
"node_modules" "include": ["index.ts", "src/**/*.ts", "demo/**/*.ts", "types/deno.d.ts"],
], // "esm": true
"include": [
"index.ts",
"src/**/*.ts",
"demo/**/*.ts",
],
} }

109
types/deno.d.ts vendored Normal file
View File

@ -0,0 +1,109 @@
declare namespace Deno {
export const version: {
/** Deno's version. For example: `"1.0.0"` */
deno: string;
/** The V8 version used by Deno. For example: `"8.0.0.0"` */
v8: string;
/** The TypeScript version used by Deno. For example: `"4.0.0"` */
typescript: string;
};
export interface NetAddr {
transport: "tcp" | "udp";
hostname: string;
port: number;
}
export type Addr = NetAddr;
export interface Closer {
close(): void;
}
export interface Reader {
/** Reads up to `p.byteLength` bytes into `p`. It resolves to the number of
* bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error
* encountered. Even if `read()` resolves to `n` < `p.byteLength`, it may
* use all of `p` as scratch space during the call. If some data is
* available but not `p.byteLength` bytes, `read()` conventionally resolves
* to what is available instead of waiting for more.
*
* When `read()` encounters end-of-file condition, it resolves to EOF
* (`null`).
*
* When `read()` encounters an error, it rejects with an error.
*
* Callers should always process the `n` > `0` bytes returned before
* considering the EOF (`null`). Doing so correctly handles I/O errors that
* happen after reading some bytes and also both of the allowed EOF
* behaviors.
*
* Implementations should not retain a reference to `p`.
*
* Use `itereateReader` from from https://deno.land/std/streams/conversion.ts to
* turn a Reader into an AsyncIterator.
*/
read(p: Uint8Array): Promise<number | null>;
}
export interface Writer {
/** Writes `p.byteLength` bytes from `p` to the underlying data stream. It
* resolves to the number of bytes written from `p` (`0` <= `n` <=
* `p.byteLength`) or reject with the error encountered that caused the
* write to stop early. `write()` must reject with a non-null error if
* would resolve to `n` < `p.byteLength`. `write()` must not modify the
* slice data, even temporarily.
*
* Implementations should not retain a reference to `p`.
*/
write(p: Uint8Array): Promise<number>;
}
export interface Conn extends Reader, Writer, Closer {
/** The local address of the connection. */
readonly localAddr: Addr;
/** The remote address of the connection. */
readonly remoteAddr: Addr;
/** The resource ID of the connection. */
readonly rid: number;
/** Shuts down (`shutdown(2)`) the write side of the connection. Most
* callers should just use `close()`. */
closeWrite(): Promise<void>;
readonly readable: ReadableStream<Uint8Array>;
readonly writable: WritableStream<Uint8Array>;
}
/** A generic network listener for stream-oriented protocols. */
export interface Listener extends AsyncIterable<Conn> {
/** Waits for and resolves to the next connection to the `Listener`. */
accept(): Promise<Conn>;
/** Close closes the listener. Any pending accept promises will be rejected
* with errors. */
close(): void;
/** Return the address of the `Listener`. */
readonly addr: Addr;
/** Return the rid of the `Listener`. */
readonly rid: number;
[Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
}
export interface ListenOptions {
port: number;
}
export function listen(
options: ListenOptions & { transport?: "tcp" }
): Listener;
export function serveHttp(conn: Conn): HttpConn;
export interface HttpConn extends AsyncIterable<FetchEvent> {
readonly rid: number;
nextRequest(): Promise<FetchEvent | null>;
close(): void;
}
}

View File

@ -1,12 +1,20 @@
// Generated using webpack-cli https://github.com/webpack/webpack-cli // Generated using webpack-cli https://github.com/webpack/webpack-cli
const path = require("path"); import path from "path";
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const isProduction = process.env.NODE_ENV == "production"; const isProduction = process.env.NODE_ENV == "production";
const config = { const config = {
output: { output: {
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "dist"),
chunkFormat: "module",
library: {
type: 'module',
},
}, },
plugins: [ plugins: [
// Add your plugins here // Add your plugins here
@ -30,9 +38,12 @@ const config = {
"http": false "http": false
} }
}, },
experiments: {
outputModule: true,
},
}; };
module.exports = () => { export default () => {
if (isProduction) { if (isProduction) {
config.mode = "production"; config.mode = "production";
config.entry = "./index.ts"; config.entry = "./index.ts";
@ -40,14 +51,23 @@ module.exports = () => {
config.mode = "development"; config.mode = "development";
config.entry = "./demo/index.ts"; config.entry = "./demo/index.ts";
} }
switch(process.env.TARGET) { switch (process.env.BUILD_TARGET) {
case "node": case "node":
config.target = "node14"; config.target = "node12";
config.output.filename = "main.node.js"; config.output.filename = "main.node.js";
break; break;
case "webworker": case "serviceworker":
config.target = "webworker"; config.target = "webworker";
config.output.filename = "main.webworker.js"; config.output.filename = "main.serviceworker.js";
break;
case "deno":
config.target = "webworker";
config.output.filename = "main.deno.js";
break;
case "cfworker":
config.mode = "production";
config.target = "webworker";
config.output.filename = "main.cfworker.js";
break; break;
default: default:
config.target = "es6"; config.target = "es6";

1599
yarn.lock

File diff suppressed because it is too large Load Diff