Created
July 28, 2024 23:42
-
-
Save davidrios/17de4718823271f8a4741a940c933b5e to your computer and use it in GitHub Desktop.
wowexport.patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/.eslintrc.json b/.eslintrc.json | |
index d171a236..614cf829 100644 | |
--- a/.eslintrc.json | |
+++ b/.eslintrc.json | |
@@ -12,7 +12,8 @@ | |
"chrome": true, | |
"crash": true, | |
"getErrorDump": true, | |
- "BigInt": true | |
+ "BigInt": true, | |
+ "mainWindow": true | |
}, | |
"env": { | |
"browser": true, | |
diff --git a/build.conf b/build.conf | |
index 9b982702..87f09e37 100644 | |
--- a/build.conf | |
+++ b/build.conf | |
@@ -7,6 +7,7 @@ | |
"manifest": { | |
"name": "wow.export", | |
"main": "./src/index.html", | |
+ "domain": "wow.export", | |
"chromium-args": "--disable-devtools --disable-raf-throttling --mixed-context --enable-node-worker --disable-logging", | |
"product_string": "wow.export", | |
"user-agent": "wow.export (%ver); %osinfo", | |
@@ -43,6 +44,26 @@ | |
}, | |
"manifestInherit": ["name", "description", "license", "version", "contributors"], | |
"builds": [ | |
+ { | |
+ "name": "win-x64-debug-hmr", | |
+ "bundle": "nwjs-sdk-v%s-win-x64.zip", | |
+ "bundleType": "ZIP", | |
+ "sourceMethod": "LINK", | |
+ "sourceTarget": "./src", | |
+ "manifestTarget": "./package.json", | |
+ "filter": { | |
+ "blacklist": [ | |
+ "locales\/[^.]+.pak(.info|)$", | |
+ "notification_helper.exe" | |
+ ], | |
+ "whitelist": [ | |
+ "locales\/en-US.pak$" | |
+ ] | |
+ }, | |
+ "manifest": { | |
+ "main": "./src/hmr-main.html" | |
+ } | |
+ }, | |
{ | |
"name": "win-x64-debug", | |
"bundle": "nwjs-sdk-v%s-win-x64.zip", | |
@@ -68,7 +89,7 @@ | |
"sourceMethod": "BUNDLE", | |
"sourceTarget": "./src", | |
"bundleConfig": { | |
- "filterExt": [".js", ".scss", ".css"], | |
+ "filterExt": [".mjs", ".js", ".scss", ".css"], | |
"sassEntry": "app.scss", | |
"sassOut": "app.css", | |
"jsEntry": "app.js" | |
@@ -125,7 +146,7 @@ | |
"sourceMethod": "BUNDLE", | |
"sourceTarget": "./src", | |
"bundleConfig": { | |
- "filterExt": [".js", ".scss", ".css"], | |
+ "filterExt": [".mjs", ".js", ".scss", ".css"], | |
"sassEntry": "app.scss", | |
"sassOut": "app.css", | |
"jsEntry": "app.js" | |
@@ -165,7 +186,7 @@ | |
"sourceMethod": "BUNDLE", | |
"sourceTarget": "./src", | |
"bundleConfig": { | |
- "filterExt": [".js", ".scss", ".css"], | |
+ "filterExt": [".mjs", ".js", ".scss", ".css"], | |
"sassEntry": "app.scss", | |
"sassOut": "app.css", | |
"jsEntry": "app.js" | |
diff --git a/build.js b/build.js | |
index 00cfa72d..18289011 100644 | |
--- a/build.js | |
+++ b/build.js | |
@@ -22,6 +22,8 @@ const uuid = require('uuid/v4'); | |
const crypto = require('crypto'); | |
const argv = process.argv.splice(2); | |
const pkg = require('pkg'); | |
+const fse = require('fs-extra'); | |
+const { rollup } = require('rollup'); | |
const CONFIG_FILE = './build.conf'; | |
const MANIFEST_FILE = './package.json'; | |
@@ -199,6 +201,25 @@ const collectFiles = async (dir, out = []) => { | |
return out; | |
}; | |
+async function removeFilesByExtension(directoryPath, targetExtension) { | |
+ try { | |
+ const entries = await fsp.readdir(directoryPath, { withFileTypes: true }); | |
+ | |
+ for (const entry of entries) { | |
+ const fullPath = path.join(directoryPath, entry.name); | |
+ if (entry.isDirectory()) { | |
+ await removeFilesByExtension(fullPath, targetExtension); | |
+ } else { | |
+ const ext = path.extname(entry.name); | |
+ if (ext.toLowerCase() === targetExtension.toLowerCase()) | |
+ await fsp.unlink(fullPath); | |
+ } | |
+ } | |
+ } catch (err) { | |
+ console.error(`Error processing directory: ${err}`); | |
+ } | |
+} | |
+ | |
/** | |
* Check if an AST node matches a structure. | |
* Returns AST_NO_MATCH or an object containing exports. | |
@@ -544,7 +565,20 @@ const deflateBuffer = util.promisify(zlib.deflate); | |
} else if (isBundle) { | |
// Bundle everything together, packaged for production release. | |
const bundleConfig = build.bundleConfig; | |
- const jsEntry = path.join(sourceDirectory, bundleConfig.jsEntry); | |
+ | |
+ const preBuildDir = path.join(outDir, '_prebuild'); | |
+ await fsp.rm(preBuildDir, { recursive: true, force: true }); | |
+ await createDirectory(preBuildDir); | |
+ await fse.copy(sourceDirectory, preBuildDir, { overwrite: true }); | |
+ const rollupBundle = await rollup({input: path.join(sourceDirectory, bundleConfig.jsEntry.replace('.js', '.mjs'))}); | |
+ await rollupBundle.write({ | |
+ file: path.join(preBuildDir, bundleConfig.jsEntry), | |
+ format: 'cjs', | |
+ inlineDynamicImports: true, | |
+ }); | |
+ removeFilesByExtension(preBuildDir, '.mjs'); | |
+ | |
+ const jsEntry = path.join(preBuildDir, bundleConfig.jsEntry); | |
log.info('Bundling sources (entry: *%s*)...', jsEntry); | |
// Make sure the source directory exists. | |
@@ -608,6 +642,10 @@ const deflateBuffer = util.promisify(zlib.deflate); | |
await fsp.writeFile(path.join(sourceTarget, bundleConfig.jsEntry), minified.code, 'utf8'); | |
log.success('*%d* sources bundled *%s* -> *%s* (*%d%*)', moduleTree.length, filesize(rawSize), filesize(minified.code.length), 100 - Math.round((minified.code.length / rawSize) * 100)); | |
+ const initModule = await fsp.readFile(path.join(sourceDirectory, 'init.js'), 'utf8'); | |
+ const minifiedInit = await terser.minify(initModule, config.terserConfig); | |
+ await fsp.writeFile(path.join(sourceTarget, 'init.js'), minifiedInit.code, 'utf8'); | |
+ | |
// Compile SCSS files into a single minified CSS output. | |
const sassEntry = path.join(sourceDirectory, bundleConfig.sassEntry); | |
log.info('Compiling stylesheet (entry: *%s*)...', sassEntry); | |
@@ -679,6 +717,8 @@ const deflateBuffer = util.promisify(zlib.deflate); | |
// Apply manifest properties defined in the config. | |
Object.assign(manifest, config.manifest); | |
+ Object.assign(manifest, build.manifest || {}); | |
+ | |
// Apply build specific meta data to the manifest. | |
Object.assign(manifest, { flavour: build.name, guid: buildGUID }); | |
diff --git a/debug.js b/debug.js | |
index 22ba971e..e01f3838 100644 | |
--- a/debug.js | |
+++ b/debug.js | |
@@ -2,11 +2,136 @@ const fs = require('fs'); | |
const path = require('path'); | |
const sass = require('sass'); | |
const childProcess = require('child_process'); | |
+const net = require('net'); | |
+const waitOn = require('wait-on'); | |
+const vite = require('vite'); | |
+const recast = require('recast'); | |
+const parser = require('recast/parsers/babel'); | |
-const nwPath = './bin/win-x64-debug/nw.exe'; | |
+const argv = process.argv.splice(2); | |
+const isHmr = argv[0] === 'hmr'; | |
+const vitePort = isHmr ? argv[1] ?? 4175 : null; | |
+ | |
+const nwPath = `./bin/win-x64-debug${isHmr ? '-hmr' : ''}/nw.exe`; | |
const srcDir = './src/'; | |
const appScss = './src/app.scss'; | |
+function convertModuleImport(moduleImport, relativeBase) { | |
+ if (moduleImport.startsWith('.')) | |
+ return path.join(path.dirname(relativeBase), moduleImport).substring(1).replace(/\\/g, '/'); | |
+ else if (moduleImport.startsWith('/')) | |
+ return path.join('src', moduleImport.substring(1)).replace(/\\/g, '/'); | |
+} | |
+ | |
+function adjustRequireSrc(ast, id) { | |
+ recast.types.visit(ast, { | |
+ visitCallExpression(sourcePath) { | |
+ const node = sourcePath.node; | |
+ if (node.callee.type === 'Identifier' && node.callee.name === 'require') { | |
+ const [arg] = node.arguments; | |
+ if (arg.type === 'StringLiteral') { | |
+ const converted = convertModuleImport(arg.value, id); | |
+ if (converted != null) | |
+ arg.value = converted; | |
+ } | |
+ } | |
+ this.traverse(sourcePath); | |
+ } | |
+ }); | |
+} | |
+ | |
+function getVueComponent(ast) { | |
+ let retDecl = null; | |
+ | |
+ recast.types.visit(ast, { | |
+ visitObjectExpression(sourcePath) { | |
+ const decl = sourcePath.value; | |
+ | |
+ // detect vue component by default export with `template` and (`setup` or `data`) properties | |
+ let hasTemplate = false; | |
+ let hasSetupData = false; | |
+ for (const prop of decl.properties) { | |
+ if (prop.key.type !== 'Identifier') | |
+ continue; | |
+ | |
+ hasTemplate = hasTemplate || prop.key.name === 'template'; | |
+ hasSetupData = hasSetupData || prop.key.name === 'setup' || prop.key.name === 'data'; | |
+ } | |
+ | |
+ if (hasTemplate && hasSetupData) { | |
+ retDecl = decl; | |
+ return false; | |
+ } | |
+ | |
+ this.traverse(sourcePath); | |
+ } | |
+ }); | |
+ | |
+ return retDecl; | |
+} | |
+ | |
+function addVueHmr(ast, id) { | |
+ let components = new Set(); | |
+ const b = recast.types.builders; | |
+ | |
+ const variableDeclarations = Object.fromEntries( | |
+ ast.program.body | |
+ .filter(node => node.type === 'VariableDeclaration') | |
+ .map(node => [node.declarations[0].id.name, node]) | |
+ ); | |
+ | |
+ for (let i = 0; i < ast.program.body.length; i++) { | |
+ const node = ast.program.body[i]; | |
+ if (!node.type.startsWith('Export')) | |
+ continue; | |
+ | |
+ try { | |
+ let vueComponent = getVueComponent(node); | |
+ if (vueComponent == null) { | |
+ const variableName = node.declaration.name ?? (node.declaration.declarations ?? '')[0]?.init?.name; | |
+ const variable = variableDeclarations[variableName] | |
+ if (variableName == null || variable == null) | |
+ continue; | |
+ | |
+ vueComponent = getVueComponent(variable); | |
+ if (vueComponent == null) | |
+ continue | |
+ } | |
+ | |
+ const name = node.type === 'ExportDefaultDeclaration' | |
+ ? 'default' | |
+ : node.declaration.declarations[0].id.name; | |
+ | |
+ const componentId = `${id}:${name}`; | |
+ components.add([componentId, name]); | |
+ | |
+ vueComponent.properties.push(b.objectProperty( | |
+ b.identifier('__hmrId'), | |
+ b.stringLiteral(componentId))); | |
+ } catch (e) { | |
+ console.error(e); | |
+ } | |
+ } | |
+ | |
+ if (components.size > 0) { | |
+ const astHot = recast.parse(` | |
+if (import.meta.hot) { | |
+ import.meta.hot.accept((newModule) => { | |
+ if (newModule == null) | |
+ return; | |
+ | |
+ ${Array.from(components.values()) | |
+ .map(([componentId, name]) => `__VUE_HMR_RUNTIME__.reload(${JSON.stringify(componentId)}, newModule.${name})`) | |
+ .join(';')}; | |
+ }); | |
+}`, { parser }); | |
+ | |
+ ast.program.body.push(...astHot.program.body); | |
+ | |
+ return true; | |
+ } | |
+} | |
+ | |
(async () => { | |
// Check if nw.exe exists | |
try { | |
@@ -40,8 +165,60 @@ const appScss = './src/app.scss'; | |
}); | |
}); | |
+ const vueHmr = { | |
+ name: 'vue-hmr', | |
+ async transformIndexHtml(html) { | |
+ return html.replace( | |
+ '<script defer type="text/javascript" src="app.js"></script>', | |
+ '<script type="module" src="app-loader.js"></script>' | |
+ ); | |
+ }, | |
+ async transform(code, id) { | |
+ const relativeId = id.substring(path.resolve(__dirname).length); | |
+ const isModule = relativeId.endsWith('.mjs'); | |
+ | |
+ if (!(relativeId.startsWith('/src') && (isModule || relativeId === '/src/init.js'))) | |
+ return; | |
+ | |
+ const ast = recast.parse(code, { sourceFileName: id, parser }); | |
+ adjustRequireSrc(ast, relativeId); | |
+ | |
+ if (isModule && !code.includes('import.meta.hot')) { | |
+ if (addVueHmr(ast, relativeId)) | |
+ console.log('vue-hmr:', relativeId); | |
+ } | |
+ | |
+ return recast.print(ast, { sourceMapName: id }); | |
+ }, | |
+ } | |
+ | |
+ if (isHmr) { | |
+ const viteServer = await vite.createServer({ | |
+ configFile: false, | |
+ root: path.join(__dirname, srcDir), | |
+ server: { port: vitePort }, | |
+ plugins: [vueHmr], | |
+ sourcemap: true, | |
+ }) | |
+ viteServer.listen(); | |
+ | |
+ await waitOn({ | |
+ resources: [`http-get://localhost:${vitePort}`], | |
+ headers: { 'accept': 'text/html' }, | |
+ }); | |
+ } | |
+ | |
+ const debugSocketPath = path.join('\\\\?\\pipe', nwPath, 'debug-window'); | |
+ let debugSocket; | |
+ const debugServer = net.createServer().listen(debugSocketPath); | |
+ debugServer.on('connection', async (socket) => { debugSocket = socket; }); | |
+ process.on('SIGINT', async function () { | |
+ debugSocket?.write('please_exit'); | |
+ setTimeout(process.exit, 500); | |
+ }); | |
+ | |
// Launch nw.exe | |
- const nwProcess = childProcess.spawn(nwPath, { stdio: 'inherit' }); | |
+ const nwProcess = childProcess.spawn(nwPath, { stdio: 'inherit', env: { ...process.env, DEBUG_SOCKET: debugSocketPath, VITE_PORT: vitePort } }); | |
// When the spawned process is closed, exit the Node.js process as well | |
nwProcess.on('close', code => { | |
diff --git a/package.json b/package.json | |
index 9b698f10..9371c151 100644 | |
--- a/package.json | |
+++ b/package.json | |
@@ -28,12 +28,18 @@ | |
"request": "^2.88.0", | |
"sass": "^1.52.1", | |
"ssh2-sftp-client": "^9.0.4", | |
- "terser": "^5.14.2", | |
"tar": "^5.0.10", | |
+ "terser": "^5.14.2", | |
"uuid": "^3.3.3" | |
}, | |
"devDependencies": { | |
+ "@msgpack/msgpack": "^2.8.0", | |
"eslint": "^6.8.0", | |
- "eslint-plugin-vue": "^6.1.2" | |
+ "eslint-plugin-vue": "^6.1.2", | |
+ "fs-extra": "^11.2.0", | |
+ "recast": "^0.23.9", | |
+ "rollup": "^4.19.1", | |
+ "vite": "^5.3.5", | |
+ "wait-on": "^7.2.0" | |
} | |
} | |
diff --git a/src/app-loader.js b/src/app-loader.js | |
new file mode 100644 | |
index 00000000..20a737ab | |
--- /dev/null | |
+++ b/src/app-loader.js | |
@@ -0,0 +1,4 @@ | |
+(async function () { | |
+ await mainWindow.isReady; | |
+ await import('./app.mjs'); | |
+})(); | |
\ No newline at end of file | |
diff --git a/src/app.js b/src/app.mjs | |
similarity index 92% | |
rename from src/app.js | |
rename to src/app.mjs | |
index 934d5a76..60f89e94 100644 | |
--- a/src/app.js | |
+++ b/src/app.mjs | |
@@ -4,12 +4,6 @@ | |
License: MIT | |
*/ | |
-// BUILD_RELEASE will be set globally by Terser during bundling allowing us | |
-// to discern a production build. However, for debugging builds it will throw | |
-// a ReferenceError without the following check. Any code that only runs when | |
-// BUILD_RELEASE is set to false will be removed as dead-code during compile. | |
-BUILD_RELEASE = typeof BUILD_RELEASE !== 'undefined'; | |
- | |
/** | |
* crash() is used to inform the user that the application has exploded. | |
* It is purposely global and primitive as we have no idea what state | |
@@ -18,7 +12,7 @@ BUILD_RELEASE = typeof BUILD_RELEASE !== 'undefined'; | |
* @param {string} errorText | |
*/ | |
let isCrashed = false; | |
-crash = (errorCode, errorText) => { | |
+window.crash = (errorCode, errorText) => { | |
// Prevent a never-ending cycle of depression. | |
if (isCrashed) | |
return; | |
@@ -69,11 +63,6 @@ if (!BUILD_RELEASE) { | |
process.on('unhandledRejection', e => crash('ERR_UNHANDLED_REJECTION', e.message)); | |
process.on('uncaughtException', e => crash('ERR_UNHANDLED_EXCEPTION', e.message)); | |
-const win = nw.Window.get(); | |
-// Launch DevTools for debug builds. | |
-if (!BUILD_RELEASE) | |
- win.showDevTools(); | |
- | |
// Imports | |
const os = require('os'); | |
const path = require('path'); | |
@@ -92,7 +81,7 @@ const ExportHelper = require('./js/casc/export-helper'); | |
const ExternalLinks = require('./js/external-links'); | |
const textureRibbon = require('./js/ui/texture-ribbon'); | |
-const Listbox = require('./js/components/listbox'); | |
+import Listbox from './js/components/listbox.mjs'; | |
const Listboxb = require('./js/components/listboxb'); | |
const Itemlistbox = require('./js/components/itemlistbox'); | |
const Checkboxlist = require('./js/components/checkboxlist'); | |
@@ -102,7 +91,7 @@ const ComboBox = require('./js/components/combobox'); | |
const Slider = require('./js/components/slider'); | |
const ModelViewer = require('./js/components/model-viewer'); | |
const MapViewer = require('./js/components/map-viewer'); | |
-const DataTable = require('./js/components/data-table'); | |
+import DataTable from './js/components/data-table.mjs'; | |
const ResizeLayer = require('./js/components/resize-layer'); | |
const ContextMenu = require('./js/components/context-menu'); | |
@@ -115,15 +104,14 @@ require('./js/ui/tab-text.js'); | |
require('./js/ui/tab-models'); | |
require('./js/ui/tab-maps'); | |
require('./js/ui/tab-items'); | |
-const TabData = require('./js/ui/tab-data'); | |
+import TabData from './js/ui/tab-data.mjs'; | |
require('./js/ui/tab-raw'); | |
require('./js/ui/tab-install'); | |
require('./js/ui/tab-characters'); | |
const RCPServer = require('./js/rcp/rcp-server'); | |
-win.setProgressBar(-1); // Reset taskbar progress in-case it's stuck. | |
-win.on('close', () => process.exit()); // Ensure we exit when window is closed. | |
+mainWindow.setProgressBar(-1); // Reset taskbar progress in-case it's stuck. | |
// Prevent files from being dropped onto the window. These are over-written | |
// later but we disable here to prevent them working if init fails. | |
@@ -560,7 +548,7 @@ document.addEventListener('click', function(e) { | |
* @param {float} val | |
*/ | |
loadPct: function(val) { | |
- win.setProgressBar(val); | |
+ mainWindow.setProgressBar(val); | |
}, | |
/** | |
@@ -573,6 +561,7 @@ document.addEventListener('click', function(e) { | |
}); | |
// Interlink error handling for Vue. | |
+ if (BUILD_RELEASE) | |
app.config.errorHandler = err => crash('ERR_VUE', err.message); | |
app.component('Listbox', Listbox); | |
diff --git a/src/index.html b/src/index.html | |
index cf6b3003..6553c03c 100644 | |
--- a/src/index.html | |
+++ b/src/index.html | |
@@ -1,8 +1,10 @@ | |
<!DOCTYPE html> | |
+<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
<script defer type="text/javascript" src="lib/vue.js"></script> | |
<script defer type="text/javascript" src="lib/three.js"></script> | |
+ <script defer type="text/javascript" src="init.js"></script> | |
<script defer type="text/javascript" src="app.js"></script> | |
<link rel="stylesheet" type="text/css" data-href="app.css" href="app.css"/> | |
<title>wow.export</title> | |
@@ -817,6 +819,7 @@ | |
</div> | |
</template> | |
</div> | |
+ | |
<div id="source-remote" :class="{ disabled: !!availableRemoteBuilds }" @click="click('source-remote', $event)"> | |
<template v-if="availableRemoteBuilds"> | |
<div class="source-builds"> | |
@@ -832,7 +835,7 @@ | |
<ul id="source-cdn" class="ui-multi-button"> | |
<li v-for="region in cdnRegions" :class="{ selected: selectedCDNRegion === region }" @click.stop="setSelectedCDN(region)"> | |
{{ region.tag.toUpperCase() }} | |
- <span v-if="region.delay !== null">{{ region.delay < 0 ? 'N/A' : region.delay + 'ms' }}</span> | |
+ <span v-if="region.delay !== null">{{ region.delay < 0 ? 'N/A' : region.delay + 'ms' }}</span> | |
</li> | |
</ul> | |
</div> | |
diff --git a/src/init.js b/src/init.js | |
new file mode 100644 | |
index 00000000..b2ffa635 | |
--- /dev/null | |
+++ b/src/init.js | |
@@ -0,0 +1,28 @@ | |
+/*! | |
+ wow.export (https://github.com/Kruithne/wow.export) | |
+ Authors: Kruithne <[email protected]> | |
+ License: MIT | |
+ */ | |
+ | |
+// BUILD_RELEASE will be set globally by Terser during bundling allowing us | |
+// to discern a production build. However, for debugging builds it will throw | |
+// a ReferenceError without the following check. Any code that only runs when | |
+// BUILD_RELEASE is set to false will be removed as dead-code during compile. | |
+BUILD_RELEASE = typeof BUILD_RELEASE !== 'undefined'; | |
+ | |
+if (!BUILD_RELEASE && typeof chrome.runtime === 'undefined') { | |
+ require('./js/init-hmr'); | |
+} else { | |
+ const win = nw.Window.get(); | |
+ win.on('close', () => process.exit()); // Ensure we exit when window is closed. | |
+ | |
+ if (!BUILD_RELEASE) | |
+ win.showDevTools(); | |
+ | |
+ mainWindow = { | |
+ setProgressBar(value) { | |
+ nw.Window.get().setProgressBar(value); | |
+ }, | |
+ isReady: new Promise((resolve) => resolve()) | |
+ } | |
+} | |
diff --git a/src/js/casc/build-cache.js b/src/js/casc/build-cache.js | |
index 34eb7686..df4ea8bd 100644 | |
--- a/src/js/casc/build-cache.js | |
+++ b/src/js/casc/build-cache.js | |
@@ -131,6 +131,7 @@ class BuildCache { | |
cacheIntegrity[filePath] = hash; | |
await fsp.writeFile(filePath, data.raw); | |
+ if (core.view != null) | |
core.view.cacheSize += data.byteLength; | |
await this.saveCacheIntegrity(); | |
diff --git a/src/js/components/data-table.js b/src/js/components/data-table.mjs | |
similarity index 99% | |
rename from src/js/components/data-table.js | |
rename to src/js/components/data-table.mjs | |
index d6655725..625623e6 100644 | |
--- a/src/js/components/data-table.js | |
+++ b/src/js/components/data-table.mjs | |
@@ -3,7 +3,7 @@ | |
Authors: Kruithne <[email protected]>, Marlamin <[email protected]> | |
License: MIT | |
*/ | |
-module.exports = { | |
+export default { | |
/** | |
* selectedOption: An array of strings denoting options shown in the menu. | |
*/ | |
diff --git a/src/js/components/listbox.js b/src/js/components/listbox.mjs | |
similarity index 96% | |
rename from src/js/components/listbox.js | |
rename to src/js/components/listbox.mjs | |
index cf4f4a59..01eb1a87 100644 | |
--- a/src/js/components/listbox.js | |
+++ b/src/js/components/listbox.mjs | |
@@ -16,7 +16,7 @@ const fid_filter = (e) => { | |
return e; | |
}; | |
-module.exports = { | |
+export default { | |
/** | |
* items: Item entries displayed in the list. | |
* filter: Optional reactive filter for items. | |
diff --git a/src/js/ui/tab-data.js b/src/js/ui/tab-data.mjs | |
similarity index 95% | |
rename from src/js/ui/tab-data.js | |
rename to src/js/ui/tab-data.mjs | |
index 1615d29f..52976925 100644 | |
--- a/src/js/ui/tab-data.js | |
+++ b/src/js/ui/tab-data.mjs | |
@@ -3,15 +3,16 @@ | |
Authors: Kruithne <[email protected]>, Marlamin <[email protected]> | |
License: MIT | |
*/ | |
-const log = require('../log'); | |
-const generics = require('../generics'); | |
-const listfile = require('../casc/listfile'); | |
-const WDCReader = require('../db/WDCReader'); | |
+ | |
+const log = require('/js/log'); | |
+const generics = require('/js/generics'); | |
+const listfile = require('/js/casc/listfile'); | |
+const WDCReader = require('/js/db/WDCReader'); | |
const path = require('path'); | |
const { inject, ref } = Vue; | |
-module.exports = { | |
+export default { | |
setup() { | |
const view = inject('view'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment