Replace vulcanize process with loose files

It's a lot easier to debug, but may have reduced startup performance.
Closes #682.
This commit is contained in:
Oliver Hamlet
2016-11-20 15:13:32 +00:00
parent 2cf52f77fe
commit cf4d38276b
11 changed files with 304 additions and 281 deletions
+3 -2
View File
@@ -524,9 +524,10 @@ add_custom_command(TARGET LOOT POST_BUILD
$<TARGET_FILE_DIR:LOOT>/resources/ui/fonts/${font})
ENDFOREACH()
# Run Vulcanize to build the UI HTML.
# Build the UI HTML.
add_custom_command(TARGET LOOT POST_BUILD
COMMAND "node" "${CMAKE_SOURCE_DIR}/scripts/vulcanize.js" ${CMAKE_SOURCE_DIR})
COMMAND "node" "${CMAKE_SOURCE_DIR}/scripts/build_ui.js"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Copy testing metadata
ExternalProject_Get_Property(testing-metadata SOURCE_DIR)
+1 -1
View File
@@ -51,7 +51,7 @@ You may also need to set `BOOST_ROOT` if CMake cannot find Boost.
### Rebuilding the HTML UI
The GUI's HTML file is automatically built when building the LOOT GUI binary, but it can also be built by running `node scripts/vulcanize.js` from the repository root.
The GUI's HTML file is automatically built when building the LOOT GUI binary, but it can also be built by running `node scripts/build_ui.js` from the repository root.
## Building The Documentation
+2 -2
View File
@@ -14,8 +14,8 @@
"private": true,
"dependencies": {
"fs-extra": "^0.30.0",
"replace": "^0.3.0",
"vulcanize": "^1.14.5"
"hydrolysis": "^1.24.1",
"replace": "^0.3.0"
},
"devDependencies": {
"bower": "^1.7.1",
File diff suppressed because it is too large Load Diff
+2 -11
View File
@@ -140,18 +140,9 @@ function createAppArchive(rootPath, releasePath, tempPath, destPath) {
});
// UI files.
fs.mkdirsSync(path.join(tempPath, 'resources', 'ui', 'css'));
fs.copySync(
path.join(releasePath, 'resources', 'ui', 'index.html'),
path.join(tempPath, 'resources', 'ui', 'index.html')
);
fs.copySync(
path.join(rootPath, 'resources', 'ui', 'css', 'dark-theme.css'),
path.join(tempPath, 'resources', 'ui', 'css', 'dark-theme.css')
);
fs.copySync(
path.join(rootPath, 'resources', 'ui', 'fonts'),
path.join(tempPath, 'resources', 'ui', 'fonts')
path.join(releasePath, 'resources', 'ui'),
path.join(tempPath, 'resources', 'ui')
);
// Documentation.
+104
View File
@@ -0,0 +1,104 @@
'use strict';
const helpers = require('./helpers');
const hyd = require('hydrolysis');
const fs = require('fs-extra');
const path = require('path');
function getHtmlImports(filePath) {
return hyd.Analyzer.analyze(filePath).then((analyzer) =>
analyzer._getDependencies(filePath)
);
}
function isString(variable) {
return typeof variable === 'string' || variable instanceof String;
}
function flattenUnique(array) {
const results = new Set();
array.forEach((element) => {
if (isString(element)) {
results.add(element);
} else if (element) {
flattenUnique(element).forEach((subelement) => {
results.add(subelement);
});
}
});
return results;
}
function getRecursiveHtmlImports(filePath, imports) {
return getHtmlImports(filePath).then((paths) =>
Promise.all(paths.map((dependency) => {
if (imports.has(dependency)) {
return null;
}
imports.add(dependency);
return getRecursiveHtmlImports(dependency, imports);
}))
).then((results) => {
flattenUnique(results).forEach((dependency) => {
imports.add(dependency);
});
return imports;
});
}
function getJavaScriptSources(filePath) {
return hyd.Analyzer.analyze(filePath).then((analyzer) =>
Object.keys(analyzer.parsedScripts).filter((script) =>
script.endsWith('.js')
)
);
}
function getRelativePath(filePath) {
if (filePath.startsWith('src/gui/html/')) {
return filePath.substring(13);
}
return filePath;
}
function normalisePaths(html) {
return html.replace(/href="(\.\.\/){3}/g, 'href="')
.replace(/src="(\.\.\/){3}/g, 'src="');
}
function copyNormalisedFile(sourceFile, destinationFile) {
const html = fs.readFileSync(sourceFile, { encoding: 'utf8' });
fs.mkdirs(path.dirname(destinationFile));
fs.writeFileSync(destinationFile, normalisePaths(html));
}
function copyFiles(pathsPromise, destinationRootPath) {
pathsPromise.then((paths) => {
paths.forEach((filePath) => {
const destinationPath = `${destinationRootPath}/${getRelativePath(filePath)}`;
if (filePath.includes('bower_components')) {
fs.copySync(filePath, destinationPath);
} else {
copyNormalisedFile(filePath, destinationPath);
}
});
});
}
helpers.getAppReleasePaths('.').forEach(releasePath => {
const index = 'src/gui/html/index.html';
const destinationRootPath = `${releasePath.path}/resources/ui`;
const imports = new Set();
copyFiles(getRecursiveHtmlImports(index, imports), destinationRootPath);
copyFiles(getJavaScriptSources(index), destinationRootPath);
fs.copySync('src/gui/html/css', `${destinationRootPath}/css`);
fs.copySync('resources/ui/css/dark-theme.css', `${destinationRootPath}/css/dark-theme.css`);
fs.copySync('resources/ui/fonts', `${destinationRootPath}/fonts`);
copyNormalisedFile(index, `${destinationRootPath}/index.html`);
// This is the only JS file referenced by a HTML import (neon-animation),
// so just hardcode it instead of recursively searching for it.
const webAnimationsJs = 'bower_components/web-animations-js/web-animations-next-lite.min.js';
fs.copySync(webAnimationsJs, `${destinationRootPath}/${webAnimationsJs}`);
});
+2 -6
View File
@@ -105,12 +105,8 @@ DestDir: "{app}\resources\l10n"; Flags: ignoreversion
Source: "{#buildir}\docs\html\*"; \
DestDir: "{app}\docs"; Flags: ignoreversion recursesubdirs
Source: "{#buildir}\Release\resources\ui\index.html"; \
DestDir: "{app}\resources\ui"; Flags: ignoreversion
Source: "resources\ui\css\dark-theme.css"; \
DestDir: "{app}\resources\ui\css"; Flags: ignoreversion
Source: "resources\ui\fonts\*"; \
DestDir: "{app}\resources\ui\fonts"; Flags: ignoreversion
Source: "{#buildir}\Release\resources\ui\*"; \
DestDir: "{app}\resources\ui"; Flags: ignoreversion recursesubdirs
Source: "resources\l10n\da\LC_MESSAGES\loot.mo"; \
DestDir: "{app}\resources\l10n\da\LC_MESSAGES"; Flags: ignoreversion
-92
View File
@@ -1,92 +0,0 @@
#!/usr/bin/env node
// Build the UI's index.html file. Takes one argument, which is the path to the
// repository's root.
/* eslint-disable no-unused-vars */
'use strict';
const path = require('path');
const fs = require('fs');
const helpers = require('./helpers');
const Vulcanize = require('vulcanize');
const mkdirp = require('mkdirp');
// Initialise from command line parameters.
let rootPath = '.';
let buildType = 'ui';
if (process.argv.length > 3) {
rootPath = process.argv[2];
buildType = process.argv[3];
} else if (process.argv.length > 2) {
rootPath = process.argv[2];
}
const vulcanize = new Vulcanize({
inlineScripts: true,
inlineCss: true,
excludes: [
'css/theme.css',
],
});
function mkdir(dir) {
try {
mkdirp.sync(dir);
} catch (e) {
if (e.code !== 'EEXIST') {
console.log(e);
}
}
}
function vulcanizeFile(inputPath, outputPath) {
// Make sure output directory exists first.
mkdir(path.dirname(outputPath));
vulcanize.process(inputPath, (err, inlinedHtml) => {
if (err) {
console.error(err);
process.exit(1);
}
fs.writeFileSync(outputPath, inlinedHtml);
});
}
function vulcanizeRelease(releasePath) {
const inputPath = path.join(rootPath, 'src', 'gui', 'html', 'index.html');
const outputPath = path.join(releasePath.path, 'resources', 'ui', 'index.html');
vulcanizeFile(inputPath, outputPath);
}
function vulcanizeTests(releasePath) {
const inputPath = path.join(rootPath, 'src', 'tests', 'gui', 'html', 'elements');
const outputPath = path.join(releasePath.path, 'html_tests', 'elements');
const tests = [
'test_editable-table.html',
'test_loot-custom-icons.html',
'test_loot-dropdown-menu.html',
'test_loot-menu.html',
'test_loot-message-dialog.html',
'test_loot-plugin-card.html',
'test_loot-plugin-editor.html',
'test_loot-plugin-item.html',
'test_loot-search-toolbar.html',
];
tests.forEach((test) => {
vulcanizeFile(path.join(inputPath, test), path.join(outputPath, test));
});
}
// Run the appropriate build(s).
const releasePaths = helpers.getAppReleasePaths(rootPath);
if (buildType === 'ui' || buildType === 'all') {
releasePaths.forEach(vulcanizeRelease);
}
if (buildType === 'tests' || buildType === 'all') {
releasePaths.forEach(vulcanizeTests);
}
+8 -2
View File
@@ -188,13 +188,19 @@
</template>
<script>
'use strict';
const editableTableHtml = document.currentScript.ownerDocument;
function getRowTemplate(templateId) {
return editableTableHtml.getElementById(templateId);
}
Polymer({ // eslint-disable-line new-cap, no-undef
is: 'editable-table',
extends: 'table',
attached() {
/* Add "add new row" row. */
const content = document.getElementById('newRow').content;
const content = getRowTemplate('newRow').content;
let row = document.importNode(content, true);
this.tBodies[0].appendChild(row);
row = this.tBodies[0].lastElementChild;
@@ -323,7 +329,7 @@
addRow(tableData) {
const rowTemplateId = this.getAttribute('data-template');
const content = document.getElementById(rowTemplateId).content;
const content = getRowTemplate(rowTemplateId).content;
let row = document.importNode(content, true);
this.tBodies[0].insertBefore(row, this.tBodies[0].lastElementChild);
row = this.tBodies[0].lastElementChild.previousElementSibling;
+3 -5
View File
@@ -47,11 +47,6 @@
<link rel="import" href="../../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../../../bower_components/paper-toolbar/paper-toolbar.html">
<link rel="import" href="../../../bower_components/paper-tooltip/paper-tooltip.html">
</head>
<!-- oncontextmenu attribute disables the right-click menu. -->
<body oncontextmenu="return false" unresolved>
<!-- This style element needs to be here so that it loads after the Vulcanized
imports, which are placed in a div that is the first child of body. -->
<style is="custom-style" include="paper-item-shared-styles">
div[drawer],
div[main] {
@@ -147,6 +142,9 @@
};
}
</style>
</head>
<!-- oncontextmenu attribute disables the right-click menu. -->
<body oncontextmenu="return false" unresolved>
<paper-drawer-panel id="container" drawer-width="33%">
<div drawer>
<paper-toolbar>
+30 -11
View File
@@ -10,9 +10,28 @@
root.loot.translateStaticText = factory();
}
}(this, () => {
function getTemplate(templateId, importHtml) {
if (importHtml === undefined) {
importHtml = templateId;
}
let template = document.getElementById(templateId);
if (!template) {
template = document
.querySelector(`link[rel="import"][href$="${importHtml}.html"]`).import;
}
template = template.querySelector(`#${templateId}`);
if (template.tagName !== 'TEMPLATE') {
template = template.querySelector('template');
}
return template.content;
}
function translatePluginCardTemplate(l10n) {
/* Plugin card template. */
const pluginCard = document.getElementById('loot-plugin-card').querySelector('template').content;
const pluginCard = getTemplate('loot-plugin-card');
pluginCard.querySelector('paper-tooltip[for=activeTick]').textContent = l10n.translate('Active Plugin');
pluginCard.querySelector('paper-tooltip[for=isMaster]').textContent = l10n.translate('Master File');
@@ -82,7 +101,7 @@
function translatePluginListItemTemplate(l10n) {
/* Plugin List Item Template */
const pluginItem = document.getElementById('loot-plugin-item').querySelector('template').content;
const pluginItem = getTemplate('loot-plugin-item');
pluginItem.querySelector('#globalPriorityTooltip').textContent = l10n.translate('Global Priority');
pluginItem.querySelector('#localPriorityTooltip').textContent = l10n.translate('Priority');
@@ -92,7 +111,7 @@
function translateMessageDialogTemplate(l10n) {
/* Plugin List Item Template */
const messageDialog = document.getElementById('loot-message-dialog').querySelector('template').content;
const messageDialog = getTemplate('loot-message-dialog');
messageDialog.getElementById('confirm').textContent = l10n.translate('OK');
messageDialog.getElementById('dismiss').textContent = l10n.translate('Cancel');
@@ -100,7 +119,7 @@
function translateFileRowTemplate(l10n) {
/* File row template */
const fileRow = document.getElementById('fileRow').content;
const fileRow = getTemplate('fileRow', 'editable-table');
fileRow.querySelector('.name').setAttribute('error-message', l10n.translate('A filename is required.'));
fileRow.querySelector('paper-tooltip').textContent = l10n.translate('Delete Row');
@@ -108,7 +127,7 @@
function translateMessageRowTemplate(l10n) {
/* Message row template */
const messageRow = document.getElementById('messageRow').content;
const messageRow = getTemplate('messageRow', 'editable-table');
messageRow.querySelector('.type').children[0].textContent = l10n.translate('Note');
messageRow.querySelector('.type').children[1].textContent = l10n.translate('Warning');
@@ -119,7 +138,7 @@
function translateTagRowTemplate(l10n) {
/* Tag row template */
const tagRow = document.getElementById('tagRow').content;
const tagRow = getTemplate('tagRow', 'editable-table');
tagRow.querySelector('.type').children[0].textContent = l10n.translate('Add');
tagRow.querySelector('.type').children[1].textContent = l10n.translate('Remove');
@@ -129,7 +148,7 @@
function translateDirtyInfoRowTemplate(l10n) {
/* Dirty Info row template */
const dirtyInfoRow = document.getElementById('dirtyInfoRow').content;
const dirtyInfoRow = getTemplate('dirtyInfoRow', 'editable-table');
dirtyInfoRow.querySelector('.crc').setAttribute('error-message', l10n.translate('A CRC is required.'));
dirtyInfoRow.querySelector('.itm').setAttribute('error-message', l10n.translate('Values must be integers.'));
@@ -141,7 +160,7 @@
function translateCleanInfoRowTemplate(l10n) {
/* Dirty Info row template */
const cleanInfoRow = document.getElementById('cleanInfoRow').content;
const cleanInfoRow = getTemplate('cleanInfoRow', 'editable-table');
cleanInfoRow.querySelector('.crc').setAttribute('error-message', l10n.translate('A CRC is required.'));
cleanInfoRow.querySelector('.utility').setAttribute('error-message', l10n.translate('A utility name is required.'));
@@ -150,7 +169,7 @@
function translateLocationRowTemplate(l10n) {
/* Location row template */
const locationRow = document.getElementById('locationRow').content;
const locationRow = getTemplate('locationRow', 'editable-table');
locationRow.querySelector('.link').setAttribute('error-message', l10n.translate('A link is required.'));
locationRow.querySelector('paper-tooltip').textContent = l10n.translate('Delete Row');
@@ -158,7 +177,7 @@
function translateGameRowTemplate(l10n) {
/* Game row template */
const gameRow = document.getElementById('gameRow').content;
const gameRow = getTemplate('gameRow', 'editable-table');
gameRow.querySelector('.name').setAttribute('error-message', l10n.translate('A name is required.'));
gameRow.querySelector('.folder').setAttribute('error-message', l10n.translate('A folder is required.'));
@@ -167,7 +186,7 @@
function translateNewRowTemplate(l10n) {
/* New row template */
const newRow = document.getElementById('newRow').content;
const newRow = getTemplate('newRow', 'editable-table');
newRow.querySelector('paper-tooltip').textContent = l10n.translate('Add New Row');
}