Merge pull request #1134 from nonameShijian/PR-Branch

将serviceWorker改为使用esm,加载时判断是否可以使用ts,sfc改为使用esm
This commit is contained in:
Spmario233 2024-03-27 17:32:29 +08:00 committed by GitHub
commit f1c75042df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 48297 additions and 48274 deletions

4
game/canUse.ts Normal file
View File

@ -0,0 +1,4 @@
// apk每次安装后第一次启动加载Service Worker会失败
// 所以每次导入这个ts判断是否会成功失败的话重启一次
export const text: string = 'ts文件导入成功';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@ import { userAgent } from "../noname/util/index.js";
const coreAndVersion = get.coreInfo(); const coreAndVersion = get.coreInfo();
const core = coreAndVersion[0], version = coreAndVersion[1]; const core = coreAndVersion[0], version = coreAndVersion[1];
//@todo: 77 -> 80
if (core === 'chrome' && !isNaN(version) && version < 77) { if (core === 'chrome' && !isNaN(version) && version < 77) {
const tip = '检测到您的浏览器内核版本小于77请及时升级浏览器或手机webview内核'; const tip = '检测到您的浏览器内核版本小于77请及时升级浏览器或手机webview内核';
console.warn(tip); console.warn(tip);

View File

@ -166,6 +166,7 @@ new Promise(resolve => {
// 使用ts compiler对ts文件进行编译 // 使用ts compiler对ts文件进行编译
const result = ts.transpile(code, { const result = ts.transpile(code, {
module: ts.ModuleKind.CommonJS, module: ts.ModuleKind.CommonJS,
//@todo: ES2019 -> ES2020
target: ts.ScriptTarget.ES2019, target: ts.ScriptTarget.ES2019,
inlineSourceMap: true, inlineSourceMap: true,
resolveJsonModule: true, resolveJsonModule: true,
@ -203,15 +204,23 @@ new Promise(resolve => {
}); });
try { try {
const registration_1 = await navigator.serviceWorker.register(`${scope}service-worker.js`, { const registration_1 = await navigator.serviceWorker.register(`${scope}service-worker.js`, {
type: 'module',
updateViaCache: "all", updateViaCache: "all",
scope, scope,
}); });
// 初次加载worker需要重新启动一次 // 初次加载worker需要重新启动一次
if (!findServiceWorker) location.reload(); if (!findServiceWorker) location.reload();
// 接收消息,暂时没用到
navigator.serviceWorker.addEventListener('message', e => { navigator.serviceWorker.addEventListener('message', e => {
console.log(e); console.log(e);
}); });
registration_1.update().catch(console.error); registration_1.update().catch(e => console.error('worker update失败', e));
if (!sessionStorage.getItem('canUseTs')) {
await import('./canUse.ts').then(({ text }) => console.log(text)).catch(() => {
sessionStorage.setItem('canUseTs', '1');
location.reload();
});
}
} catch (e_1) { } catch (e_1) {
console.log('serviceWorker加载失败: ', e_1); console.log('serviceWorker加载失败: ', e_1);
} }

View File

@ -172279,4 +172279,7 @@ ${e.message}`;
})(); })();
if (typeof module !== "undefined" && module.exports) { if (typeof module !== "undefined" && module.exports) {
module.exports = ts; module.exports = ts;
}
if (typeof globalThis !== "undefined") {
globalThis.ts = ts;
} }

View File

@ -1,39 +1,39 @@
/**
* @type { ServiceWorkerGlobalScope } 提供ServiceWorker的代码提示
*/
// @ts-ignore
var self = globalThis;
// 以副作用导入typescript以保证require也可以同步使用
import './game/typescript.js';
/** /**
* @type { import('typescript') } * @type { import('typescript') }
*/ */
var ts; var ts = globalThis.ts;
importScripts('./game/typescript.js'); // sfc以正常的esmodule使用
/** import * as sfc from './game/compiler-sfc.esm-browser.js';
* @type { import('./game/compiler-sfc.browser.js') }
*/
var sfc;
importScripts('./game/compiler-sfc.browser.js');
// @ts-ignore
if (typeof ts != 'undefined') { if (typeof ts != 'undefined') {
console.log(`ts loaded`); console.log(`ts loaded`, ts.version);
} else { } else {
console.log(`ts undefined`); console.error(`ts undefined`);
} }
// @ts-ignore
if (typeof sfc != 'undefined') { if (typeof sfc != 'undefined') {
console.log(`sfc loaded`); console.log(`sfc loaded`, sfc.version);
sfc.registerTS(() => ts); sfc.registerTS(() => ts);
} else { } else {
console.log(`sfc undefined`); console.error(`sfc undefined`);
} }
console.log('serviceWorker version 2.3'); console.log('serviceWorker version 2.3');
self.addEventListener("install", (event) => { self.addEventListener("install", (event) => {
// The promise that skipWaiting() returns can be safely ignored. // The promise that skipWaiting() returns can be safely ignored.
// @ts-ignore
self.skipWaiting(); self.skipWaiting();
}); });
self.addEventListener("activate", (event) => { self.addEventListener("activate", (event) => {
// 当一个 service worker 被初始注册时,页面在下次加载之前不会使用它。 claim() 方法会立即控制这些页面 // 当一个 service worker 被初始注册时,页面在下次加载之前不会使用它。 claim() 方法会立即控制这些页面
// @ts-ignore event.waitUntil(self.clients.claim());
event.waitUntil(clients.claim());
}); });
self.addEventListener('message', event => { self.addEventListener('message', event => {
@ -46,7 +46,6 @@ self.addEventListener('message', event => {
const vueFileMap = new Map(); const vueFileMap = new Map();
self.addEventListener('fetch', event => { self.addEventListener('fetch', event => {
// @ts-ignore
const request = event.request; const request = event.request;
if (typeof request.url != 'string') return console.log(request); if (typeof request.url != 'string') return console.log(request);
if (vueFileMap.has(request.url)) { if (vueFileMap.has(request.url)) {
@ -63,10 +62,9 @@ self.addEventListener('fetch', event => {
if (!['.ts', '.json', '.vue', 'css'].some(ext => request.url.endsWith(ext))) return; if (!['.ts', '.json', '.vue', 'css'].some(ext => request.url.endsWith(ext))) return;
if (request.url.endsWith('.d.ts')) return; if (request.url.endsWith('.d.ts')) return;
if (request.url.endsWith('.json') || request.url.endsWith('css')) { if (request.url.endsWith('.json') || request.url.endsWith('css')) {
// @ts-ignore
if (!event.request.headers.get('origin')) return; if (!event.request.headers.get('origin')) return;
} }
// 请求ts文件 // 请求文件
const res = fetch(request.url, { const res = fetch(request.url, {
method: request.method, method: request.method,
mode: "no-cors", mode: "no-cors",
@ -74,18 +72,19 @@ self.addEventListener('fetch', event => {
"Content-Type": "text/plain" "Content-Type": "text/plain"
}), }),
}); });
// @ts-ignore // 修改请求结果
event.respondWith( event.respondWith(
res.then(res => { res.then(res => {
if (res.status != 200) return res; if (res.status != 200) return res;
console.log('正在编译', request.url); console.log('正在编译', request.url);
return res.text().then(text => { return res.text().then(text => {
let js; let js = '';
if (request.url.endsWith('.json')) { if (request.url.endsWith('.json')) {
js = `export default ${ text }`; js = `export default ${ text }`;
} else if (request.url.endsWith('.ts')) { } else if (request.url.endsWith('.ts')) {
js = ts.transpile(text, { js = ts.transpile(text, {
module: ts.ModuleKind.ES2015, module: ts.ModuleKind.ES2015,
//@todo: ES2019 -> ES2020
target: ts.ScriptTarget.ES2019, target: ts.ScriptTarget.ES2019,
inlineSourceMap: true, inlineSourceMap: true,
resolveJsonModule: true, resolveJsonModule: true,
@ -97,7 +96,7 @@ self.addEventListener('fetch', event => {
// 后续处理sourceMap合并 // 后续处理sourceMap合并
const { descriptor } = sfc.parse(text, { filename: request.url, sourceMap: true }); const { descriptor } = sfc.parse(text, { filename: request.url, sourceMap: true });
// console.log({ descriptor }); // console.log({ descriptor });
const hasScoped = descriptor.styles.some((s) => s.scoped); const hasScoped = descriptor.styles.some(s => s.scoped);
// 编译 script因为可能有 script setup还要进行 css 变量注入 // 编译 script因为可能有 script setup还要进行 css 变量注入
const script = sfc.compileScript(descriptor, { const script = sfc.compileScript(descriptor, {
id: scopeId, id: scopeId,
@ -111,27 +110,38 @@ self.addEventListener('fetch', event => {
}); });
// 用于存放代码,最后 join('\n') 合并成一份完整代码 // 用于存放代码,最后 join('\n') 合并成一份完整代码
const codeList = []; const codeList = [];
// 保存url并且拼接参数
const url = new URL(request.url);
const scriptSearchParams = new URLSearchParams(url.search.slice(1));
scriptSearchParams.append('type', 'script');
const templateSearchParams = new URLSearchParams(url.search.slice(1));
templateSearchParams.append('type', 'template');
vueFileMap.set( vueFileMap.set(
request.url + '?type=script', url.origin + url.pathname + '?' + scriptSearchParams.toString(),
// 重写 default // 重写 default
sfc.rewriteDefault(script.attrs && script.attrs.lang == 'ts' ? ts.transpile(script.content, { sfc.rewriteDefault(script.attrs && script.attrs.lang == 'ts' ? ts.transpile(script.content, {
module: ts.ModuleKind.ES2015, module: ts.ModuleKind.ES2015,
//@todo: ES2019 -> ES2020
target: ts.ScriptTarget.ES2019, target: ts.ScriptTarget.ES2019,
inlineSourceMap: true, inlineSourceMap: true,
resolveJsonModule: true, resolveJsonModule: true,
esModuleInterop: true, esModuleInterop: true,
}, request.url + '?type=script') : script.content, "__sfc_main__") }, url.origin + url.pathname + '?' + scriptSearchParams.toString()) : script.content, "__sfc_main__")
.replace(`const __sfc_main__`, `export const __sfc_main__`) .replace(`const __sfc_main__`, `export const __sfc_main__`)
// import vue重新指向 // import vue重新指向
.replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`) .replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`)
.replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`) .replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`)
); );
codeList.push(`import { __sfc_main__ } from '${ request.url }?type=script'`);
codeList.push(`import { __sfc_main__ } from '${ url.origin + url.pathname + '?' + scriptSearchParams.toString() }'`);
codeList.push(`__sfc_main__.__scopeId = '${ scopeId }'`); codeList.push(`__sfc_main__.__scopeId = '${ scopeId }'`);
// 编译模板,转换成 render 函数 // 编译模板,转换成 render 函数
const template = sfc.compileTemplate({ const template = sfc.compileTemplate({
source: descriptor.template.content, source: descriptor.template ? descriptor.template.content : '',
filename: request.url, // 用于错误提示 filename: request.url, // 用于错误提示
id: scopeId, id: scopeId,
scoped: hasScoped, scoped: hasScoped,
@ -140,13 +150,15 @@ self.addEventListener('fetch', event => {
} }
}); });
vueFileMap.set(request.url + '?type=template', template.code vueFileMap.set(
url.origin + url.pathname + '?' + templateSearchParams.toString(),
template.code
// .replace(`function render(_ctx, _cache) {`, str => str + 'console.log(_ctx);') // .replace(`function render(_ctx, _cache) {`, str => str + 'console.log(_ctx);')
.replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`) .replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`)
.replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`) .replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`)
); );
codeList.push(`import { render } from '${ request.url }?type=template'`); codeList.push(`import { render } from '${ url.origin + url.pathname + '?' + templateSearchParams.toString() }'`);
codeList.push(`__sfc_main__.render = render;`); codeList.push(`__sfc_main__.render = render;`);
codeList.push(`export default __sfc_main__;`); codeList.push(`export default __sfc_main__;`);
// 一个 Vue 文件,可能有多个 style 标签 // 一个 Vue 文件,可能有多个 style 标签
@ -180,11 +192,12 @@ self.addEventListener('fetch', event => {
"Content-Type": "text/javascript" "Content-Type": "text/javascript"
}), }),
}); });
console.log(request.url, '编译成功');
return rep; return rep;
}) })
}) })
.catch(e => { .catch(e => {
console.log(e); console.error(request.url, '编译失败: ', e);
throw e; throw e;
}) })
); );