Merge pull request #1167 from nonameShijian/PR-Branch
使import可以解析node内部模块
This commit is contained in:
commit
614e153722
22
index.html
22
index.html
|
@ -6,6 +6,28 @@
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="viewport" content="user-scalable=no, viewport-fit=cover">
|
<meta name="viewport" content="user-scalable=no, viewport-fit=cover">
|
||||||
<title>无名杀</title>
|
<title>无名杀</title>
|
||||||
|
<script>
|
||||||
|
if (typeof window.require == 'function' &&
|
||||||
|
typeof window.process == 'object' &&
|
||||||
|
typeof window.__dirname == 'string') {
|
||||||
|
// 使importMap解析node内置模块
|
||||||
|
const builtinModules = require('module').builtinModules;
|
||||||
|
if (Array.isArray(builtinModules)) {
|
||||||
|
const importMap = {
|
||||||
|
imports: {}
|
||||||
|
};
|
||||||
|
for (const module of builtinModules) {
|
||||||
|
importMap.imports[module] =
|
||||||
|
importMap.imports[`node:${module}`] =
|
||||||
|
`./noname-builtinModules/${module}`
|
||||||
|
}
|
||||||
|
const im = document.createElement('script');
|
||||||
|
im.type = 'importmap';
|
||||||
|
im.textContent = JSON.stringify(importMap);
|
||||||
|
document.currentScript.after(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
"use strict";
|
"use strict";
|
||||||
(() => {
|
(() => {
|
||||||
|
|
|
@ -360,9 +360,6 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (game.download) {
|
else if (game.download) {
|
||||||
// if (!confirm('请保证一小时内没有进行过素材和游戏更新,否则会请求失败,是否继续?')) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
if (!localStorage.getItem('noname_authorization') && !sessionStorage.getItem('noname_authorization')) {
|
if (!localStorage.getItem('noname_authorization') && !sessionStorage.getItem('noname_authorization')) {
|
||||||
if (confirm('素材更新或许会直接超过每小时的访问限制,是否输入您github的token以解除访问每小时60次的限制?')) await gainAuthorization();
|
if (confirm('素材更新或许会直接超过每小时的访问限制,是否输入您github的token以解除访问每小时60次的限制?')) await gainAuthorization();
|
||||||
}
|
}
|
||||||
|
@ -372,9 +369,24 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
checkAssetButton.innerHTML = '检查素材更新';
|
checkAssetButton.innerHTML = '检查素材更新';
|
||||||
checkAssetButton.disabled = false;
|
checkAssetButton.disabled = false;
|
||||||
}
|
}
|
||||||
// 暂定更新这四个文件夹
|
const assetDirs = [];
|
||||||
const assetDirs = ['audio', 'font', 'image', 'theme'];
|
if (lib.config.asset_font) {
|
||||||
|
assetDirs.push('font');
|
||||||
|
}
|
||||||
|
if (lib.config.asset_audio) {
|
||||||
|
assetDirs.push('audio');
|
||||||
|
}
|
||||||
|
if (lib.config.asset_image) {
|
||||||
|
assetDirs.push('image');
|
||||||
|
}
|
||||||
const files = await Promise.all(assetDirs.map(dir => flattenRepositoryFiles(dir)));
|
const files = await Promise.all(assetDirs.map(dir => flattenRepositoryFiles(dir)));
|
||||||
|
assetDirs.forEach((value, index) => {
|
||||||
|
const arr = files[index];
|
||||||
|
const size = arr.reduce((previous, current) => {
|
||||||
|
return previous + current.size;
|
||||||
|
}, 0);
|
||||||
|
game.saveConfig(`asset_${value}_size`, parseSize(size));
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* @param { any[] } arr
|
* @param { any[] } arr
|
||||||
* @param { Function } predicate
|
* @param { Function } predicate
|
||||||
|
@ -389,55 +401,10 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
const result = await asyncFilter(files.flat(), async v => {
|
const result = await asyncFilter(files.flat(), async v => {
|
||||||
return v.size != (await game.promises.readFile(v.path)).length;
|
return v.size != (await game.promises.readFile(v.path)).length;
|
||||||
}).then(arr => arr.map(v => v.path));
|
}).then(arr => arr.map(v => v.path));
|
||||||
console.log(result);
|
console.log('需要更新的文件有:', result);
|
||||||
const progress = createProgress('正在更新素材包.zip');
|
game.print('需要更新的文件有:', result);
|
||||||
/**
|
const finish = async () => {
|
||||||
* @type {progress}
|
await lib.init.promises.js('game', 'asset.js');
|
||||||
*/
|
|
||||||
let unZipProgress;
|
|
||||||
request('noname.unitedrhythmized.club/api', (receivedBytes, total, filename) => {
|
|
||||||
if (typeof filename == 'string') {
|
|
||||||
progress.setFileName(filename);
|
|
||||||
}
|
|
||||||
let received = 0, max = 0;
|
|
||||||
if (total) {
|
|
||||||
max = +(total / (1024 * 1024)).toFixed(1)
|
|
||||||
} else {
|
|
||||||
max = 1000;
|
|
||||||
}
|
|
||||||
received = +(receivedBytes / (1024 * 1024)).toFixed(1);
|
|
||||||
if (received > max) max = received;
|
|
||||||
progress.setProgressMax(max);
|
|
||||||
progress.setProgressValue(received);
|
|
||||||
}, {
|
|
||||||
method: 'post',
|
|
||||||
body: JSON.stringify({
|
|
||||||
fileList: result
|
|
||||||
})
|
|
||||||
}).then(async blob => {
|
|
||||||
progress.remove();
|
|
||||||
const zip = await get.promises.zip();
|
|
||||||
zip.load(await blob.arrayBuffer());
|
|
||||||
const entries = Object.entries(zip.files);
|
|
||||||
let root;
|
|
||||||
const hiddenFileFlags = ['.', '_'];
|
|
||||||
unZipProgress = createProgress('正在解压' + progress.getFileName(), entries.length);
|
|
||||||
let i = 0;
|
|
||||||
for (const [key, value] of entries) {
|
|
||||||
unZipProgress.setProgressValue(i++);
|
|
||||||
const fileName = typeof root == 'string' && key.startsWith(root) ? key.replace(root, '') : key;
|
|
||||||
if (hiddenFileFlags.includes(fileName[0])) continue;
|
|
||||||
if (value.dir) {
|
|
||||||
await game.promises.createDir(fileName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unZipProgress.setFileName(fileName);
|
|
||||||
const [path, name] = [fileName.split('/').slice(0, -1).join('/'), fileName.split('/').slice(-1).join('/')];
|
|
||||||
game.print(`${fileName}(${i}/${entries.length})`);
|
|
||||||
await game.promises.writeFile(value.asArrayBuffer(), path, name);
|
|
||||||
}
|
|
||||||
unZipProgress.remove();
|
|
||||||
await lib.init.promises.js('game', 'update.js');
|
|
||||||
if (Array.isArray(window.noname_asset_list)) {
|
if (Array.isArray(window.noname_asset_list)) {
|
||||||
game.saveConfig('asset_version', window.noname_asset_list[0]);
|
game.saveConfig('asset_version', window.noname_asset_list[0]);
|
||||||
delete window.noname_asset_list;
|
delete window.noname_asset_list;
|
||||||
|
@ -446,12 +413,65 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
game.reload();
|
game.reload();
|
||||||
}
|
}
|
||||||
refresh();
|
refresh();
|
||||||
}).catch(e => {
|
};
|
||||||
if (progress.parentNode) progress.remove();
|
if (result.length > 0) {
|
||||||
if (unZipProgress && unZipProgress.parentNode) unZipProgress.remove();
|
const progress = createProgress('正在更新素材包.zip');
|
||||||
refresh();
|
/**
|
||||||
throw e;
|
* @type {progress}
|
||||||
});
|
*/
|
||||||
|
let unZipProgress;
|
||||||
|
request('noname.unitedrhythmized.club/api', (receivedBytes, total, filename) => {
|
||||||
|
if (typeof filename == 'string') {
|
||||||
|
progress.setFileName(filename);
|
||||||
|
}
|
||||||
|
let received = 0, max = 0;
|
||||||
|
if (total) {
|
||||||
|
max = +(total / (1024 * 1024)).toFixed(1)
|
||||||
|
} else {
|
||||||
|
max = 1000;
|
||||||
|
}
|
||||||
|
received = +(receivedBytes / (1024 * 1024)).toFixed(1);
|
||||||
|
if (received > max) max = received;
|
||||||
|
progress.setProgressMax(max);
|
||||||
|
progress.setProgressValue(received);
|
||||||
|
}, {
|
||||||
|
method: 'post',
|
||||||
|
body: JSON.stringify({
|
||||||
|
fileList: result.concat('game/asset.js')
|
||||||
|
})
|
||||||
|
}).then(async blob => {
|
||||||
|
progress.remove();
|
||||||
|
const zip = await get.promises.zip();
|
||||||
|
zip.load(await blob.arrayBuffer());
|
||||||
|
const entries = Object.entries(zip.files);
|
||||||
|
let root;
|
||||||
|
const hiddenFileFlags = ['.', '_'];
|
||||||
|
unZipProgress = createProgress('正在解压' + progress.getFileName(), entries.length);
|
||||||
|
let i = 0;
|
||||||
|
for (const [key, value] of entries) {
|
||||||
|
unZipProgress.setProgressValue(i++);
|
||||||
|
const fileName = typeof root == 'string' && key.startsWith(root) ? key.replace(root, '') : key;
|
||||||
|
if (hiddenFileFlags.includes(fileName[0])) continue;
|
||||||
|
if (value.dir) {
|
||||||
|
await game.promises.createDir(fileName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unZipProgress.setFileName(fileName);
|
||||||
|
const [path, name] = [fileName.split('/').slice(0, -1).join('/'), fileName.split('/').slice(-1).join('/')];
|
||||||
|
game.print(`${fileName}(${i}/${entries.length})`);
|
||||||
|
await game.promises.writeFile(value.asArrayBuffer(), path, name);
|
||||||
|
}
|
||||||
|
unZipProgress.remove();
|
||||||
|
await finish();
|
||||||
|
}).catch(e => {
|
||||||
|
if (progress.parentNode) progress.remove();
|
||||||
|
if (unZipProgress && unZipProgress.parentNode) unZipProgress.remove();
|
||||||
|
refresh();
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('此版本不支持游戏内更新素材,请手动更新');
|
alert('此版本不支持游戏内更新素材,请手动更新');
|
||||||
|
@ -563,11 +583,11 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
if (!this.classList.toggle('on')) {
|
if (!this.classList.toggle('on')) {
|
||||||
game.saveConfig('asset_toggle_off', true);
|
game.saveConfig('asset_toggle_off', true);
|
||||||
[
|
[
|
||||||
span2, span2_br, span2_check,
|
/* span2, span2_br, span2_check,*/
|
||||||
span3, span3_br, span3_check,
|
span3, span3_br, span3_check,
|
||||||
span4, span4_br, span4_check,
|
span4, span4_br, span4_check,
|
||||||
span5, span5_br, span5_check,
|
span5, span5_br, span5_check,
|
||||||
span6, span6_br, span6_check,
|
/* span6, span6_br, span6_check,*/
|
||||||
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
||||||
display: 'none'
|
display: 'none'
|
||||||
}));
|
}));
|
||||||
|
@ -575,11 +595,11 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
else {
|
else {
|
||||||
game.saveConfig('asset_toggle_off');
|
game.saveConfig('asset_toggle_off');
|
||||||
[
|
[
|
||||||
span2, span2_br, span2_check,
|
/* span2, span2_br, span2_check,*/
|
||||||
span3, span3_br, span3_check,
|
span3, span3_br, span3_check,
|
||||||
span4, span4_br, span4_check,
|
span4, span4_br, span4_check,
|
||||||
span5, span5_br, span5_check,
|
span5, span5_br, span5_check,
|
||||||
span6, span6_br, span6_check,
|
/* span6, span6_br, span6_check,*/
|
||||||
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
||||||
display: ''
|
display: ''
|
||||||
}));
|
}));
|
||||||
|
@ -588,24 +608,11 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
span1.listen(span1.toggle);
|
span1.listen(span1.toggle);
|
||||||
li2.lastChild.appendChild(span1);
|
li2.lastChild.appendChild(span1);
|
||||||
|
|
||||||
var span6_br = ui.create.node('br');
|
// var span6_br = ui.create.node('br');
|
||||||
li2.lastChild.appendChild(span6_br);
|
// li2.lastChild.appendChild(span6_br);
|
||||||
|
// var span2_br = ui.create.node('br');
|
||||||
|
|
||||||
var span5 = ui.create.div('', '图片素材(精简,126MB)');
|
var span4 = ui.create.div('', `字体素材(${ lib.config.asset_font_size || '23.4MB' })`);
|
||||||
span5.style.fontSize = 'small';
|
|
||||||
span5.style.lineHeight = '16px';
|
|
||||||
var span5_check = document.createElement('input');
|
|
||||||
span5_check.type = 'checkbox';
|
|
||||||
span5_check.style.marginLeft = '5px';
|
|
||||||
if (lib.config.asset_image) {
|
|
||||||
span5_check.checked = true;
|
|
||||||
}
|
|
||||||
span5_check.onchange = function () {
|
|
||||||
game.saveConfig('asset_image', this.checked);
|
|
||||||
};
|
|
||||||
var span2_br = ui.create.node('br');
|
|
||||||
|
|
||||||
var span4 = ui.create.div('', '字体素材(48MB)');
|
|
||||||
span4.style.fontSize = 'small';
|
span4.style.fontSize = 'small';
|
||||||
span4.style.lineHeight = '16px';
|
span4.style.lineHeight = '16px';
|
||||||
li2.lastChild.appendChild(span4);
|
li2.lastChild.appendChild(span4);
|
||||||
|
@ -622,7 +629,7 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
var span3_br = ui.create.node('br');
|
var span3_br = ui.create.node('br');
|
||||||
li2.lastChild.appendChild(span3_br);
|
li2.lastChild.appendChild(span3_br);
|
||||||
|
|
||||||
var span3 = ui.create.div('', '音效素材(125MB)');
|
var span3 = ui.create.div('', `音效素材(${ lib.config.asset_audio_size || '350MB' })`);
|
||||||
span3.style.fontSize = 'small';
|
span3.style.fontSize = 'small';
|
||||||
span3.style.lineHeight = '16px';
|
span3.style.lineHeight = '16px';
|
||||||
li2.lastChild.appendChild(span3);
|
li2.lastChild.appendChild(span3);
|
||||||
|
@ -639,49 +646,60 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM
|
||||||
var span4_br = ui.create.node('br');
|
var span4_br = ui.create.node('br');
|
||||||
li2.lastChild.appendChild(span4_br);
|
li2.lastChild.appendChild(span4_br);
|
||||||
|
|
||||||
var span2 = ui.create.div('', '皮肤素材(351MB)');
|
// var span2 = ui.create.div('', '皮肤素材(351MB)');
|
||||||
span2.style.fontSize = 'small';
|
// span2.style.fontSize = 'small';
|
||||||
span2.style.lineHeight = '16px';
|
// span2.style.lineHeight = '16px';
|
||||||
li2.lastChild.appendChild(span2);
|
// li2.lastChild.appendChild(span2);
|
||||||
var span2_check = document.createElement('input');
|
// var span2_check = document.createElement('input');
|
||||||
span2_check.type = 'checkbox';
|
// span2_check.type = 'checkbox';
|
||||||
span2_check.style.marginLeft = '5px';
|
// span2_check.style.marginLeft = '5px';
|
||||||
if (lib.config.asset_skin) {
|
// if (lib.config.asset_skin) {
|
||||||
span2_check.checked = true;
|
// span2_check.checked = true;
|
||||||
|
// }
|
||||||
|
// span2_check.onchange = function () {
|
||||||
|
// game.saveConfig('asset_skin', this.checked);
|
||||||
|
// };
|
||||||
|
// li2.lastChild.appendChild(span2_check);
|
||||||
|
var span5 = ui.create.div('', `图片素材(${lib.config.asset_image_size || '363MB'})`);
|
||||||
|
span5.style.fontSize = 'small';
|
||||||
|
span5.style.lineHeight = '16px';
|
||||||
|
li2.lastChild.appendChild(span5);
|
||||||
|
var span5_check = document.createElement('input');
|
||||||
|
span5_check.type = 'checkbox';
|
||||||
|
span5_check.style.marginLeft = '5px';
|
||||||
|
if (lib.config.asset_image) {
|
||||||
|
span5_check.checked = true;
|
||||||
}
|
}
|
||||||
span2_check.onchange = function () {
|
span5_check.onchange = function () {
|
||||||
game.saveConfig('asset_skin', this.checked);
|
// @ts-ignore
|
||||||
|
game.saveConfig('asset_image', this.checked);
|
||||||
};
|
};
|
||||||
li2.lastChild.appendChild(span2_check);
|
li2.lastChild.appendChild(span5_check);
|
||||||
var span5_br = ui.create.node('br');
|
var span5_br = ui.create.node('br');
|
||||||
li2.lastChild.appendChild(span5_br);
|
li2.lastChild.appendChild(span5_br);
|
||||||
|
// li2.lastChild.appendChild(span2_br);
|
||||||
|
|
||||||
|
// var span6 = ui.create.div('', '图片素材(完整,203MB)');
|
||||||
li2.lastChild.appendChild(span5);
|
// span6.style.fontSize = 'small';
|
||||||
li2.lastChild.appendChild(span5_check);
|
// span6.style.lineHeight = '16px';
|
||||||
li2.lastChild.appendChild(span2_br);
|
// li2.lastChild.appendChild(span6);
|
||||||
|
// var span6_check = document.createElement('input');
|
||||||
var span6 = ui.create.div('', '图片素材(完整,203MB)');
|
// span6_check.type = 'checkbox';
|
||||||
span6.style.fontSize = 'small';
|
// span6_check.style.marginLeft = '5px';
|
||||||
span6.style.lineHeight = '16px';
|
// if (lib.config.asset_full) {
|
||||||
li2.lastChild.appendChild(span6);
|
// span6_check.checked = true;
|
||||||
var span6_check = document.createElement('input');
|
// }
|
||||||
span6_check.type = 'checkbox';
|
// span6_check.onchange = function () {
|
||||||
span6_check.style.marginLeft = '5px';
|
// game.saveConfig('asset_full', this.checked);
|
||||||
if (lib.config.asset_full) {
|
// };
|
||||||
span6_check.checked = true;
|
// li2.lastChild.appendChild(span6_check);
|
||||||
}
|
|
||||||
span6_check.onchange = function () {
|
|
||||||
game.saveConfig('asset_full', this.checked);
|
|
||||||
};
|
|
||||||
li2.lastChild.appendChild(span6_check);
|
|
||||||
|
|
||||||
[
|
[
|
||||||
span2, span2_br, span2_check,
|
/* span2, span2_br, span2_check,*/
|
||||||
span3, span3_br, span3_check,
|
span3, span3_br, span3_check,
|
||||||
span4, span4_br, span4_check,
|
span4, span4_br, span4_check,
|
||||||
span5, span5_br, span5_check,
|
span5, span5_br, span5_check,
|
||||||
span6, span6_br, span6_check,
|
/* span6, span6_br, span6_check,*/
|
||||||
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
].forEach(item => HTMLDivElement.prototype.css.call(item, {
|
||||||
display: 'none'
|
display: 'none'
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -59,146 +59,161 @@ self.addEventListener('fetch', event => {
|
||||||
event.respondWith(rep);
|
event.respondWith(rep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!['.ts', '.json', '.vue', 'css'].some(ext => request.url.endsWith(ext))) return;
|
if (!['.ts', '.json', '.vue', 'css'].some(ext => request.url.endsWith(ext)) && !request.url.replace(location.origin, '').startsWith('/noname-builtinModules/')) 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')) {
|
||||||
if (!event.request.headers.get('origin')) return;
|
if (!event.request.headers.get('origin')) return;
|
||||||
}
|
}
|
||||||
// 请求原文件
|
if (request.url.replace(location.origin, '').startsWith('/noname-builtinModules/')) {
|
||||||
const res = fetch(request.url, {
|
const moduleName = request.url.replace(location.origin + '/noname-builtinModules/', '');
|
||||||
method: request.method,
|
console.log('正在编译', moduleName);
|
||||||
mode: "no-cors",
|
let js = `const module = require('${ moduleName }');\nexport default module;`;
|
||||||
headers: new Headers({
|
const rep = new Response(new Blob([js], { type: "text/javascript" }), {
|
||||||
"Content-Type": "text/plain"
|
status: 200,
|
||||||
}),
|
statusText: "OK",
|
||||||
});
|
headers: new Headers({
|
||||||
// 修改请求结果
|
"Content-Type": "text/javascript"
|
||||||
event.respondWith(
|
}),
|
||||||
res.then(res => {
|
});
|
||||||
if (res.status != 200) return res;
|
console.log(moduleName, '编译成功');
|
||||||
console.log('正在编译', request.url);
|
event.respondWith(Promise.resolve(rep));
|
||||||
return res.text().then(text => {
|
} else {
|
||||||
let js = '';
|
// 请求原文件
|
||||||
if (request.url.endsWith('.json')) {
|
const res = fetch(request.url, {
|
||||||
js = `export default ${ text }`;
|
method: request.method,
|
||||||
} else if (request.url.endsWith('.ts')) {
|
mode: "no-cors",
|
||||||
js = ts.transpile(text, {
|
headers: new Headers({
|
||||||
module: ts.ModuleKind.ES2015,
|
"Content-Type": "text/plain"
|
||||||
//@todo: ES2019 -> ES2020
|
}),
|
||||||
target: ts.ScriptTarget.ES2019,
|
});
|
||||||
inlineSourceMap: true,
|
// 修改请求结果
|
||||||
resolveJsonModule: true,
|
event.respondWith(
|
||||||
esModuleInterop: true,
|
res.then(res => {
|
||||||
}, request.url);
|
if (res.status != 200) return res;
|
||||||
} else if (request.url.endsWith('.vue')) {
|
console.log('正在编译', request.url);
|
||||||
const id = Date.now().toString();
|
return res.text().then(text => {
|
||||||
const scopeId = `data-v-${ id }`;
|
let js = '';
|
||||||
// 后续处理sourceMap合并
|
if (request.url.endsWith('.json')) {
|
||||||
const { descriptor } = sfc.parse(text, { filename: request.url, sourceMap: true });
|
js = `export default ${ text }`;
|
||||||
// console.log({ descriptor });
|
} else if (request.url.endsWith('.ts')) {
|
||||||
const hasScoped = descriptor.styles.some(s => s.scoped);
|
js = ts.transpile(text, {
|
||||||
// 编译 script,因为可能有 script setup,还要进行 css 变量注入
|
|
||||||
const script = sfc.compileScript(descriptor, {
|
|
||||||
id: scopeId,
|
|
||||||
inlineTemplate: true,
|
|
||||||
templateOptions: {
|
|
||||||
scoped: hasScoped,
|
|
||||||
compilerOptions: {
|
|
||||||
scopeId: hasScoped ? scopeId : undefined,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// 用于存放代码,最后 join('\n') 合并成一份完整代码
|
|
||||||
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(
|
|
||||||
url.origin + url.pathname + '?' + scriptSearchParams.toString(),
|
|
||||||
// 重写 default
|
|
||||||
sfc.rewriteDefault(script.attrs && script.attrs.lang == 'ts' ? ts.transpile(script.content, {
|
|
||||||
module: ts.ModuleKind.ES2015,
|
module: ts.ModuleKind.ES2015,
|
||||||
//@todo: ES2019 -> ES2020
|
//@todo: ES2019 -> ES2020
|
||||||
target: ts.ScriptTarget.ES2019,
|
target: ts.ScriptTarget.ES2019,
|
||||||
inlineSourceMap: true,
|
inlineSourceMap: true,
|
||||||
resolveJsonModule: true,
|
resolveJsonModule: true,
|
||||||
esModuleInterop: true,
|
esModuleInterop: true,
|
||||||
}, url.origin + url.pathname + '?' + scriptSearchParams.toString()) : script.content, "__sfc_main__")
|
}, request.url);
|
||||||
.replace(`const __sfc_main__`, `export const __sfc_main__`)
|
} else if (request.url.endsWith('.vue')) {
|
||||||
// import vue重新指向
|
const id = Date.now().toString();
|
||||||
|
const scopeId = `data-v-${ id }`;
|
||||||
|
// 后续处理sourceMap合并
|
||||||
|
const { descriptor } = sfc.parse(text, { filename: request.url, sourceMap: true });
|
||||||
|
// console.log({ descriptor });
|
||||||
|
const hasScoped = descriptor.styles.some(s => s.scoped);
|
||||||
|
// 编译 script,因为可能有 script setup,还要进行 css 变量注入
|
||||||
|
const script = sfc.compileScript(descriptor, {
|
||||||
|
id: scopeId,
|
||||||
|
inlineTemplate: true,
|
||||||
|
templateOptions: {
|
||||||
|
scoped: hasScoped,
|
||||||
|
compilerOptions: {
|
||||||
|
scopeId: hasScoped ? scopeId : undefined,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 用于存放代码,最后 join('\n') 合并成一份完整代码
|
||||||
|
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(
|
||||||
|
url.origin + url.pathname + '?' + scriptSearchParams.toString(),
|
||||||
|
// 重写 default
|
||||||
|
sfc.rewriteDefault(script.attrs && script.attrs.lang == 'ts' ? ts.transpile(script.content, {
|
||||||
|
module: ts.ModuleKind.ES2015,
|
||||||
|
//@todo: ES2019 -> ES2020
|
||||||
|
target: ts.ScriptTarget.ES2019,
|
||||||
|
inlineSourceMap: true,
|
||||||
|
resolveJsonModule: true,
|
||||||
|
esModuleInterop: true,
|
||||||
|
}, url.origin + url.pathname + '?' + scriptSearchParams.toString()) : script.content, "__sfc_main__")
|
||||||
|
.replace(`const __sfc_main__`, `export const __sfc_main__`)
|
||||||
|
// import vue重新指向
|
||||||
|
.replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`)
|
||||||
|
.replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`)
|
||||||
|
);
|
||||||
|
|
||||||
|
codeList.push(`import { __sfc_main__ } from '${ url.origin + url.pathname + '?' + scriptSearchParams.toString() }'`);
|
||||||
|
codeList.push(`__sfc_main__.__scopeId = '${ scopeId }'`);
|
||||||
|
|
||||||
|
// 编译模板,转换成 render 函数
|
||||||
|
const template = sfc.compileTemplate({
|
||||||
|
source: descriptor.template ? descriptor.template.content : '',
|
||||||
|
filename: request.url, // 用于错误提示
|
||||||
|
id: scopeId,
|
||||||
|
scoped: hasScoped,
|
||||||
|
compilerOptions: {
|
||||||
|
scopeId: hasScoped ? scopeId : undefined,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
vueFileMap.set(
|
||||||
|
url.origin + url.pathname + '?' + templateSearchParams.toString(),
|
||||||
|
template.code
|
||||||
|
// .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 { __sfc_main__ } from '${ url.origin + url.pathname + '?' + scriptSearchParams.toString() }'`);
|
codeList.push(`import { render } from '${ url.origin + url.pathname + '?' + templateSearchParams.toString() }'`);
|
||||||
codeList.push(`__sfc_main__.__scopeId = '${ scopeId }'`);
|
codeList.push(`__sfc_main__.render = render;`);
|
||||||
|
codeList.push(`export default __sfc_main__;`);
|
||||||
// 编译模板,转换成 render 函数
|
// 一个 Vue 文件,可能有多个 style 标签
|
||||||
const template = sfc.compileTemplate({
|
let styleIndex = 0;
|
||||||
source: descriptor.template ? descriptor.template.content : '',
|
for (const styleBlock of descriptor.styles) {
|
||||||
filename: request.url, // 用于错误提示
|
const styleCode = sfc.compileStyle({
|
||||||
id: scopeId,
|
source: styleBlock.content,
|
||||||
scoped: hasScoped,
|
id,
|
||||||
compilerOptions: {
|
filename: request.url,
|
||||||
scopeId: hasScoped ? scopeId : undefined,
|
scoped: styleBlock.scoped,
|
||||||
|
});
|
||||||
|
const varName = `el${ styleIndex }`;
|
||||||
|
const styleDOM = `let ${ varName } = document.createElement('style');\n${ varName }.innerHTML = \`${ styleCode.code }\`;\ndocument.body.append(${ varName });`;
|
||||||
|
codeList.push(styleDOM);
|
||||||
}
|
}
|
||||||
});
|
js = codeList.join('\n');
|
||||||
|
// console.log(js);
|
||||||
vueFileMap.set(
|
} else if (request.url.endsWith('css')) {
|
||||||
url.origin + url.pathname + '?' + templateSearchParams.toString(),
|
const id = Date.now().toString();
|
||||||
template.code
|
const scopeId = `data-v-${ id }`;
|
||||||
// .replace(`function render(_ctx, _cache) {`, str => str + 'console.log(_ctx);')
|
js = `const style = document.createElement('style');
|
||||||
.replaceAll(`from "vue"`, `from "/game/vue.esm-browser.js"`)
|
style.setAttribute('type', 'text/css');
|
||||||
.replaceAll(`from 'vue'`, `from '/game/vue.esm-browser.js'`)
|
style.setAttribute('data-vue-dev-id', \`${ scopeId }\`);
|
||||||
);
|
style.textContent = ${ JSON.stringify(text) };
|
||||||
|
document.head.appendChild(style);`;
|
||||||
codeList.push(`import { render } from '${ url.origin + url.pathname + '?' + templateSearchParams.toString() }'`);
|
|
||||||
codeList.push(`__sfc_main__.render = render;`);
|
|
||||||
codeList.push(`export default __sfc_main__;`);
|
|
||||||
// 一个 Vue 文件,可能有多个 style 标签
|
|
||||||
let styleIndex = 0;
|
|
||||||
for (const styleBlock of descriptor.styles) {
|
|
||||||
const styleCode = sfc.compileStyle({
|
|
||||||
source: styleBlock.content,
|
|
||||||
id,
|
|
||||||
filename: request.url,
|
|
||||||
scoped: styleBlock.scoped,
|
|
||||||
});
|
|
||||||
const varName = `el${ styleIndex }`;
|
|
||||||
const styleDOM = `let ${ varName } = document.createElement('style');\n${ varName }.innerHTML = \`${ styleCode.code }\`;\ndocument.body.append(${ varName });`;
|
|
||||||
codeList.push(styleDOM);
|
|
||||||
}
|
}
|
||||||
js = codeList.join('\n');
|
const rep = new Response(new Blob([js], { type: "text/javascript" }), {
|
||||||
// console.log(js);
|
status: 200,
|
||||||
} else if (request.url.endsWith('css')) {
|
statusText: "OK",
|
||||||
const id = Date.now().toString();
|
headers: new Headers({
|
||||||
const scopeId = `data-v-${ id }`;
|
"Content-Type": "text/javascript"
|
||||||
js = `const style = document.createElement('style');
|
}),
|
||||||
style.setAttribute('type', 'text/css');
|
});
|
||||||
style.setAttribute('data-vue-dev-id', \`${ scopeId }\`);
|
console.log(request.url, '编译成功');
|
||||||
style.textContent = ${ JSON.stringify(text) };
|
return rep;
|
||||||
document.head.appendChild(style);`;
|
})
|
||||||
}
|
|
||||||
const rep = new Response(new Blob([js], { type: "text/javascript" }), {
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
headers: new Headers({
|
|
||||||
"Content-Type": "text/javascript"
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
console.log(request.url, '编译成功');
|
|
||||||
return rep;
|
|
||||||
})
|
})
|
||||||
})
|
.catch(e => {
|
||||||
.catch(e => {
|
console.error(request.url, '编译失败: ', e);
|
||||||
console.error(request.url, '编译失败: ', e);
|
throw e;
|
||||||
throw e;
|
})
|
||||||
})
|
);
|
||||||
);
|
}
|
||||||
});
|
});
|
Loading…
Reference in New Issue