我想在 Web 应用程序和服务工作者之间共享源模块(类),但找不到单独使用 typescript 的方法。使用 amd 时,只要我导入一个模块,“self”就不再在初始线程上。所有这些模块源都需要同步加载,这与我的 Web 应用程序不同,我可以在其中异步 require() 它。我尝试使用 es2015 模块而不是 amd,但遇到“无法在模块外使用 import 语句”。即使它成功了,我也会遇到与 amd 相同的问题。似乎无法绕过服务工作者使用 importScripts() 的需要。
如果我可以指示 typescript 我从 tsconfig.json 文件中针对工作人员,理论上它可以生成 serviceworker 样式的导入,但我看不到这样的支持。所以对于我的问题:
有没有办法从打字稿构建模块化服务工作者解决方案?
失败:
import { Module1 } from "./mods/module1.js";
self.addEventListener("install", (event: any) => {
new Module1("from index");
});
我怀疑没有好的答案,因为 importScripts 不返回任何东西。这些脚本需要在 repo 中注册。如果 almond.js 有一个同步模式,我认为这会解决我的问题,因为 Typescript 会生成这个:
define(["require", "exports", "./mods/module1.js"], function (require, exports, module1_js_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
self.addEventListener("install", function (event) {
new module1_js_1.Module1("from index");
});
});
如果 require() 不是异步的,我可以在同一个线程上访问“self”,事情应该会顺利进行。从 almond.js 中删除 setTimeout() 会破坏加载器。
更新:有一种使用 amd 和 almond 加载器的模式:
self.importScripts("../node_modules/almond/almond.js");
self.addEventListener("install", event => {
requirejs(["worker/index"], (worker: { run: () => void }) => worker.run());
});
我刚刚开发它,所以可能会遇到限制。worker/index.ts 看起来像这样:
import {Module1} from "../mods/module1";
export function run() {
new Module1("running from worker");
}
因此将开发人员返回到标准打字稿模块。
更新:
以下 tsconfig.json 效果很好:
{
"compilerOptions": {
"outFile": "./app/service_worker.js",
"target": "ES2015",
"module": "amd",
"strict": true,
"inlineSourceMap": true
},
"files": ["./app/service_worker.ts","./app/serviceworker/index.ts"]
}
使用这个 package.json:
{
"name": "pwa-poc",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"server": "cd server && tsc && node server.js",
"worker": "tsc -p tsconfig-worker.json",
"test": "cd tests && tsc -p tsconfig.json",
"app": "tsc -p tsconfig.json",
"watch:worker": "npm run worker -- -w",
"watch:test": "npm run test -- -w",
"watch:app": "npm run app -- -w",
"all": "npm-run-all -p server watch:worker watch:app watch:test"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"almond": "^0.3.3",
"typescript": "^3.8.2",
"xml2js": "^0.4.23"
},
"devDependencies": {
"@types/chai": "^4.2.10",
"@types/mocha": "^7.0.2",
"chai": "^4.2.0",
"mocha": "^7.1.0",
"npm-run-all": "^4.1.5"
}
}
重要的依赖是杏仁。生成的 index.js 包含所有 amd define 实例,almond 实现了 define 方法。
index.html 文件加载包:
<body class="theme">
<script src="../static/almond.js"></script>
<script src="index.js"></script>
<script>
window.addEventListener('load', () => {
require(["index"], App => {
App.run();
});
});
</script>
</body>
run() 可用,因为 index.ts 导出它:
import { TableExplorer } from "./ux/TableExplorer";
import { MetaForm } from "./ux/MetaForm";
import { DataGrid } from "./ux/DataGrid";
import { saveFormData } from "./ux/saveFormData";
import { getServices } from "./fun/getServices";
export async function run() {
navigator.serviceWorker.register("./service_worker.js");
const params = new URLSearchParams(window.location.search);
const table = params.get("table");
const family = params.get("family") || "";
const offline = !!params.get("offline");
// ask service work to install all metadata
const registration = await navigator.serviceWorker.ready;
offline && registration.sync.register("offline");
const services = getServices();
if (!table) {
const explorer = new TableExplorer({ services, family, useLinks: true });
document.body.appendChild(await explorer.render());
return;
}
document.title = table;
const form = new MetaForm({ family, table, services });
await form.render();
document.body.appendChild(form.form);
form.form.onsubmit = event => {
saveFormData({ family, table, services, form });
event.preventDefault();
grid.refresh();
};
const grid = new DataGrid({ family, table, services });
await grid.render();
document.body.appendChild(grid.grid);
}
tsconfig-worker.json:
{
"compilerOptions": {
"outFile": "./app/service_worker.js",
"target": "ES2015",
"module": "amd",
"strict": true,
"inlineSourceMap": true
},
"files": ["./app/service_worker.ts","./app/serviceworker/index.ts"]
}
最后,service_worker.ts:
declare var requirejs: Function;
self.importScripts("../static/almond.js");
requirejs(["serviceworker/index"], (worker: { run: (worker:any) => void }) => worker.run(self));