Update build tooling
This commit is contained in:
parent
d239943580
commit
c379c23786
|
@ -14,3 +14,4 @@ app/src/core/*.js.map
|
|||
|
||||
tests.js
|
||||
app/build
|
||||
build
|
||||
|
|
|
@ -10,19 +10,11 @@
|
|||
<style> html, body {
|
||||
background: #59c6ff;
|
||||
margin: 0;
|
||||
overscroll-behavior-y: contain;
|
||||
} </style>
|
||||
|
||||
<link rel="stylesheet" href="./assets/fonts/fonts.css">
|
||||
|
||||
<script>
|
||||
// Register service worker if supported.
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener('load', function() {
|
||||
navigator.serviceWorker.register("service-worker.js");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="module" src="node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
||||
<script type="module" src="./src/elements/app.js"></script>
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"shell": "src/elements/app.js",
|
||||
"sources": [
|
||||
"src/**/*.js",
|
||||
"vendor/**/*.js",
|
||||
"manifest/**",
|
||||
"package.json",
|
||||
"manifest.json"
|
||||
|
@ -15,11 +14,5 @@
|
|||
"assets/**/*"
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"npm": true,
|
||||
"builds": [
|
||||
{
|
||||
"name": "web",
|
||||
"preset": "es6-bundled"
|
||||
}
|
||||
]
|
||||
"npm": true
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var { buildCordova } = require("../../lib/build");
|
||||
var path = require("path");
|
||||
const { buildCordova } = require("../../lib/build");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = function(context) {
|
||||
const platforms = context.opts.cordova.platforms;
|
||||
|
|
24
gulpfile.js
24
gulpfile.js
|
@ -3,11 +3,11 @@
|
|||
|
||||
const gulp = require("gulp");
|
||||
const { argv } = require("yargs");
|
||||
const { buildChrome, buildElectron, compile, buildDashboard } = require("./lib/build");
|
||||
const http = require("http");
|
||||
const st = require("st");
|
||||
const { buildChrome, buildElectron, bundle, buildDashboard } = require("./lib/build");
|
||||
const { updateLanguageFiles, buildTranslationsFile } = require("./lib/locale");
|
||||
|
||||
gulp.task("bundle", () => bundle(argv.dest, argv));
|
||||
|
||||
// Deploy a minified/built version of the app to a given destination folder
|
||||
gulp.task("build", () => {
|
||||
let promises = [];
|
||||
|
@ -24,19 +24,6 @@ gulp.task("build", () => {
|
|||
return Promise.all(promises);
|
||||
});
|
||||
|
||||
gulp.task("compile", () => {
|
||||
return compile(argv.watch);
|
||||
});
|
||||
|
||||
gulp.task("serve", function() {
|
||||
var port = argv.port || 8080;
|
||||
console.log("Serving the app on a local server on port 8080. " +
|
||||
"To view it, open your web browser and navigate to http://localhost:8080/app/");
|
||||
http.createServer(
|
||||
st({ path: "", cache: false, index: "index.html" })
|
||||
).listen(port);
|
||||
});
|
||||
|
||||
const supportedLanguages = ["en", "de", "es"];
|
||||
|
||||
gulp.task("update-langfiles", () => {
|
||||
|
@ -44,13 +31,10 @@ gulp.task("update-langfiles", () => {
|
|||
});
|
||||
|
||||
gulp.task("build-transfile", () => {
|
||||
return buildTranslationsFile("resources/translations/",
|
||||
"app/src/ui/locale/translations.js", supportedLanguages);
|
||||
return buildTranslationsFile("resources/translations/", "app/src/ui/locale/translations.js", supportedLanguages);
|
||||
});
|
||||
|
||||
gulp.task("build-dashboard", () => {
|
||||
const { dest, watch } = argv;
|
||||
return buildDashboard(dest, watch);
|
||||
});
|
||||
|
||||
gulp.task("default", ["compile", "serve"]);
|
||||
|
|
363
lib/build.js
363
lib/build.js
|
@ -10,12 +10,11 @@ const insertLines = require("gulp-insert-lines");
|
|||
const { exec } = require("child_process");
|
||||
const builder = require("electron-builder");
|
||||
const archiver = require("archiver");
|
||||
const browserify = require("browserify");
|
||||
const source = require("vinyl-source-stream");
|
||||
const tsify = require("tsify");
|
||||
const watchify = require("watchify");
|
||||
const gutil = require("gulp-util");
|
||||
const { getSignVendorPath } = require("electron-builder-lib/out/windowsCodeSign");
|
||||
const { PolymerProject, getOptimizeStreams, addServiceWorker } = require("polymer-build");
|
||||
const mergeStream = require("merge-stream");
|
||||
const { Transform } = require("stream");
|
||||
const { projectConfig, swConfig } = require("./config");
|
||||
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
const appDir = path.join(projectRoot, "app");
|
||||
|
@ -23,7 +22,7 @@ const appDir = path.join(projectRoot, "app");
|
|||
function promisify(f) {
|
||||
return function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
f(...arguments, (err) => {
|
||||
f(...arguments, err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
|
@ -38,85 +37,8 @@ const copy = promisify(fs.copy);
|
|||
const rmdir = promisify(rimraf);
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
function compileCore(watch = false) {
|
||||
let b = browserify(`${appDir}/src/core/main.ts`, {
|
||||
standalone: "padlock",
|
||||
cache: {},
|
||||
packageCache: {},
|
||||
debug: true
|
||||
}).plugin(tsify);
|
||||
|
||||
function bundle() {
|
||||
const stream = b.bundle();
|
||||
stream.on("error", (e) => gutil.log(e.message));
|
||||
|
||||
return stream
|
||||
.pipe(source("padlock.js"))
|
||||
.pipe(gulp.dest(`${appDir}/src/`));
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
b.plugin(watchify);
|
||||
b.on("update", bundle);
|
||||
}
|
||||
|
||||
return bundle();
|
||||
}
|
||||
|
||||
function compileCoreLite(watch = false) {
|
||||
let b = browserify(`${appDir}/src/core/main-lite.ts`, {
|
||||
standalone: "padlock",
|
||||
cache: {},
|
||||
packageCache: {},
|
||||
debug: true
|
||||
}).plugin(tsify);
|
||||
|
||||
function bundle() {
|
||||
const stream = b.bundle();
|
||||
stream.on("error", (e) => gutil.log(e.message));
|
||||
|
||||
return stream
|
||||
.pipe(source("padlock-lite.js"))
|
||||
.pipe(gulp.dest(`${appDir}/src/`));
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
b.plugin(watchify);
|
||||
b.on("update", bundle);
|
||||
}
|
||||
|
||||
return bundle();
|
||||
}
|
||||
|
||||
function compileTests(watch = false) {
|
||||
let b = browserify(`${projectRoot}/test/main.ts`, {
|
||||
cache: {},
|
||||
packageCache: {},
|
||||
debug: true
|
||||
}).plugin(tsify);
|
||||
|
||||
function bundle() {
|
||||
return b.bundle()
|
||||
.pipe(source("tests.js"))
|
||||
.pipe(gulp.dest(`${projectRoot}/test/`));
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
b.plugin(watchify);
|
||||
b.on("update", bundle);
|
||||
}
|
||||
|
||||
return bundle();
|
||||
}
|
||||
|
||||
function compile(watch = false) {
|
||||
compileCore(watch);
|
||||
compileCoreLite(watch);
|
||||
compileTests(watch);
|
||||
}
|
||||
|
||||
function copyFiles(source, dest, files) {
|
||||
return Promise.all(files.map((f) => copy(path.resolve(source, f), path.resolve(dest, f))));
|
||||
return Promise.all(files.map(f => copy(path.resolve(source, f), path.resolve(dest, f))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,14 +66,86 @@ function pexec(command, logStderr = true, logStdout) {
|
|||
});
|
||||
}
|
||||
|
||||
function bundle(dest = "build") {
|
||||
const bundler = `${projectRoot}/node_modules/polymer-bundler/lib/bin/polymer-bundler.js`;
|
||||
const crisper = `${projectRoot}/node_modules/crisper/bin/crisper`;
|
||||
const flags = `--inline-scripts --inline-css -r ${appDir}`;
|
||||
let cmd = `node ${bundler} ${flags} index.html | node ${crisper} --html ${dest}/index.html --js ${dest}/build.js`;
|
||||
return rmdir(dest)
|
||||
.then(() => copyFiles(appDir, dest, ["assets"]))
|
||||
.then(() => pexec(cmd));
|
||||
function streamToPromise(stream) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
stream.on("finish", resolve);
|
||||
stream.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
class InjectSWLoader extends Transform {
|
||||
constructor(path) {
|
||||
super({ objectMode: true });
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
_transform(file, _, done) {
|
||||
if (file.path == path) {
|
||||
let contents = file.contents.toString();
|
||||
contents = contents.replace(
|
||||
/<head>/i,
|
||||
`<head>
|
||||
<script>
|
||||
// Register service worker if supported.
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", function() {
|
||||
navigator.serviceWorker.register("service-worker.js");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
`
|
||||
);
|
||||
file.contents = new Buffer(contents);
|
||||
}
|
||||
done(null, file);
|
||||
}
|
||||
}
|
||||
|
||||
async function bundle(dest = "build", { bundle, amd, sw, compile }) {
|
||||
dest = path.resolve(projectRoot, dest);
|
||||
|
||||
process.chdir(appDir);
|
||||
|
||||
const project = new PolymerProject(projectConfig);
|
||||
const entryPoint = path.resolve(appDir, project.config.entrypoint);
|
||||
|
||||
let stream = mergeStream(project.sources(), project.dependencies());
|
||||
|
||||
if (sw) {
|
||||
stream = stream.pipe(new InjectSWLoader(entryPoint));
|
||||
}
|
||||
|
||||
if (bundle) {
|
||||
stream = stream.pipe(project.bundler());
|
||||
}
|
||||
|
||||
const optStreams = getOptimizeStreams({
|
||||
js: {
|
||||
moduleResolution: project.config.moduleResolution,
|
||||
transformModulesToAmd: amd,
|
||||
compile: compile
|
||||
},
|
||||
entrypointPath: project.config.entrypoint,
|
||||
rootDir: project.config.root
|
||||
});
|
||||
|
||||
for (const s of optStreams) {
|
||||
stream = stream.pipe(s);
|
||||
}
|
||||
|
||||
await rmdir(dest);
|
||||
stream = stream.pipe(gulp.dest(dest));
|
||||
|
||||
await streamToPromise(stream);
|
||||
|
||||
if (sw) {
|
||||
await addServiceWorker({
|
||||
buildRoot: dest,
|
||||
project: project,
|
||||
swPrecacheConfig: swConfig,
|
||||
bundled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildChrome() {
|
||||
|
@ -168,107 +162,101 @@ function buildChrome() {
|
|||
Object.assign(manifest, { version: v, description, author });
|
||||
return writeFile(path.join(buildDir, "manifest.json"), JSON.stringify(manifest, null, " "));
|
||||
})
|
||||
.then(() => new Promise((resolve, reject) => {
|
||||
let output = fs.createWriteStream(path.join(dest, `padlock-v${version}-chrome.zip`));
|
||||
let archive = archiver.create("zip");
|
||||
archive.directory(buildDir, "padlock");
|
||||
archive.on("error", reject);
|
||||
archive.on("finish", resolve);
|
||||
archive.pipe(output);
|
||||
archive.finalize();
|
||||
}));
|
||||
.then(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
let output = fs.createWriteStream(path.join(dest, `padlock-v${version}-chrome.zip`));
|
||||
let archive = archiver.create("zip");
|
||||
archive.directory(buildDir, "padlock");
|
||||
archive.on("error", reject);
|
||||
archive.on("finish", resolve);
|
||||
archive.pipe(output);
|
||||
archive.finalize();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function buildElectron(options) {
|
||||
const buildDir = path.join("dist", "electron");
|
||||
const { name, version, description, author, licence, homepage, dependencies, main } =
|
||||
require(path.join(projectRoot, "package.json"));
|
||||
async function buildElectron(options) {
|
||||
const buildDir = path.join("app", "build", "electron");
|
||||
const distDir = path.join("dist", "electron");
|
||||
const { name, version, description, author, licence, homepage, dependencies, main } = require(path.join(
|
||||
projectRoot,
|
||||
"package.json"
|
||||
));
|
||||
const appMeta = {
|
||||
name, version, description, author, licence, homepage, dependencies, main,
|
||||
name,
|
||||
version,
|
||||
description,
|
||||
author,
|
||||
licence,
|
||||
homepage,
|
||||
dependencies,
|
||||
main,
|
||||
productName: "Padlock"
|
||||
};
|
||||
|
||||
return rmdir(buildDir)
|
||||
.then(() => copyFiles(".", "dist/electron", [ "main.js" ]))
|
||||
.then(() => writeFile(path.join(buildDir, "package.json"), JSON.stringify(appMeta, null, " ")))
|
||||
.then(() => pexec(`pushd ${buildDir} && npm install --production && popd`))
|
||||
.then(() => bundle(path.join(buildDir, "app")))
|
||||
.then(() => builder.build({
|
||||
mac: options.mac && ["default"],
|
||||
win: options.win && ["nsis"],
|
||||
linux: options.linux && ["AppImage"],
|
||||
config: {
|
||||
appId: "com.maklesoft.padlock",
|
||||
publish: {
|
||||
provider: "github",
|
||||
owner: "maklesoft",
|
||||
repo: "padlock"
|
||||
},
|
||||
directories: {
|
||||
buildResources: "resources/electron",
|
||||
app: "dist/electron",
|
||||
output: "dist"
|
||||
},
|
||||
win: {
|
||||
publisherName: "Open Source Developer, Martin Kleinschrodt",
|
||||
sign: (opts) => {
|
||||
return getSignVendorPath().then((vendorPath) => {
|
||||
const signTool = path.join(vendorPath, "windows-10", process.arch, "signtool.exe");
|
||||
const cmd = `${signTool} sign /n "${opts.options.publisherName}" ` +
|
||||
`/t http://time.certum.pl/ /fd sha1 /v "${opts.path}"`;
|
||||
await pexec("cd ${appDir} && polymer build --name electron --js-compile --bundle --js-transform-modules-to-amd");
|
||||
await rmdir(distDir);
|
||||
await copy(buildDir, distDir);
|
||||
await copy("./main.js", distDir);
|
||||
await writeFile(path.join(distDir, "package.json"), JSON.stringify(appMeta, null, " "));
|
||||
await pexec(`cd ${distDir} && npm install --production`);
|
||||
await builder.build({
|
||||
mac: options.mac && ["default"],
|
||||
win: options.win && ["nsis"],
|
||||
linux: options.linux && ["AppImage"],
|
||||
config: {
|
||||
appId: "com.maklesoft.padlock",
|
||||
publish: {
|
||||
provider: "github",
|
||||
owner: "maklesoft",
|
||||
repo: "padlock"
|
||||
},
|
||||
directories: {
|
||||
buildResources: "resources/electron",
|
||||
app: "dist/electron",
|
||||
output: "dist"
|
||||
},
|
||||
win: {
|
||||
publisherName: "Open Source Developer, Martin Kleinschrodt",
|
||||
sign: opts => {
|
||||
return getSignVendorPath().then(vendorPath => {
|
||||
const signTool = path.join(vendorPath, "windows-10", process.arch, "signtool.exe");
|
||||
const cmd =
|
||||
`${signTool} sign /n "${opts.options.publisherName}" ` +
|
||||
`/t http://time.certum.pl/ /fd sha1 /v "${opts.path}"`;
|
||||
|
||||
return pexec(cmd, true, true);
|
||||
});
|
||||
}
|
||||
},
|
||||
linux: {
|
||||
category: "Utility"
|
||||
},
|
||||
protocols: {
|
||||
name: "Padlock",
|
||||
schemes: ["padlock"]
|
||||
return pexec(cmd, true, true);
|
||||
});
|
||||
}
|
||||
},
|
||||
publish: options.release && "always"
|
||||
}));
|
||||
}
|
||||
|
||||
function streamToPromise(stream) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
stream.on("finish", resolve);
|
||||
stream.on("error", reject);
|
||||
linux: {
|
||||
category: "Utility"
|
||||
},
|
||||
protocols: {
|
||||
name: "Padlock",
|
||||
schemes: ["padlock"]
|
||||
}
|
||||
},
|
||||
publish: options.release && "always"
|
||||
});
|
||||
}
|
||||
|
||||
function buildCordova(platform, dest) {
|
||||
// iOS requires the source files to be bundled into a single file
|
||||
// whereas doing that causes problems on Android, so we leave the files as-is.
|
||||
const prepFiles = platform === "ios" ? bundle(dest) :
|
||||
copyFiles(appDir, dest, ["bower_components", "assets", "src", "index.html"]);
|
||||
async function buildCordova(platform, dest) {
|
||||
await pexec("cd ${appDir} && polymer build --name cordova");
|
||||
await copy(path.resolve(appDir, "build", "cordova", dest));
|
||||
|
||||
return prepFiles
|
||||
.then(() => {
|
||||
let lines = "\n<script src=\"cordova.js\"></script>\n";
|
||||
const stream = gulp
|
||||
.src("index.html", { cwd: dest })
|
||||
.pipe(
|
||||
insertLines({
|
||||
after: /<head>/i,
|
||||
lineAfter: '\n<script src="cordova.js"></script>\n'
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(dest));
|
||||
|
||||
if (platform === "ios") {
|
||||
lines += `
|
||||
<script>
|
||||
window.customElements = window.customElements || {};
|
||||
window.customElements.forcePolyfill = true;
|
||||
window.ShadyDOM = {force: true};
|
||||
</script>
|
||||
`;
|
||||
}
|
||||
|
||||
const stream = gulp.src("index.html", {cwd: dest})
|
||||
.pipe(insertLines({
|
||||
"after": /<head>/i,
|
||||
"lineAfter": lines
|
||||
}))
|
||||
.pipe(gulp.dest(dest));
|
||||
|
||||
return streamToPromise(stream);
|
||||
});
|
||||
return streamToPromise(stream);
|
||||
}
|
||||
|
||||
function buildDashboard(dest = "build/dashboard", watch = false) {
|
||||
|
@ -277,7 +265,8 @@ function buildDashboard(dest = "build/dashboard", watch = false) {
|
|||
const flags = `--inline-scripts --inline-css -r ${appDir}`;
|
||||
const source = "src/cloud-dashboard/cloud-dashboard.html";
|
||||
const targetDir = `${dest}/elements/cloud-dashboard`;
|
||||
const bundleCmd = `node ${bundler} ${flags} ${source} | node ${crisper} --html ` +
|
||||
const bundleCmd =
|
||||
`node ${bundler} ${flags} ${source} | node ${crisper} --html ` +
|
||||
`${targetDir}/cloud-dashboard.html --js ${targetDir}/cloud-dashboard.js`;
|
||||
|
||||
function doIt() {
|
||||
|
@ -295,17 +284,15 @@ function buildDashboard(dest = "build/dashboard", watch = false) {
|
|||
fs.watch("app", { recursive: true }, doIt);
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
// rmdir(dest)
|
||||
.then(() => fs.ensureDir(targetDir))
|
||||
.then(() => doIt());
|
||||
|
||||
return (
|
||||
Promise.resolve()
|
||||
// rmdir(dest)
|
||||
.then(() => fs.ensureDir(targetDir))
|
||||
.then(() => doIt())
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
compileCore,
|
||||
compileTests,
|
||||
compile,
|
||||
bundle,
|
||||
buildChrome,
|
||||
buildElectron,
|
||||
|
|
6
main.js
6
main.js
|
@ -7,13 +7,15 @@ const url = require("url");
|
|||
const os = require("os");
|
||||
const fs = require("fs-extra");
|
||||
const uuid = require("uuid/v4");
|
||||
const { debug, test } = require("yargs").argv;
|
||||
const { debug, test, dir } = require("yargs").argv;
|
||||
const ElectronStore = require("electron-store");
|
||||
|
||||
if (debug || test) {
|
||||
app.setPath("userData", path.join(app.getPath("temp"), app.getName()));
|
||||
}
|
||||
|
||||
const indexPath = path.resolve(__dirname, test ? "test" : dir || "app", "index.html");
|
||||
|
||||
const defaultDBPath = path.join(app.getPath("userData"), "data.pls");
|
||||
const settings = (global.settings = new ElectronStore({
|
||||
name: "settings",
|
||||
|
@ -203,7 +205,7 @@ function createWindow() {
|
|||
// and load the index.html of the app.
|
||||
win.loadURL(
|
||||
url.format({
|
||||
pathname: path.resolve(__dirname, test ? "test/index.html" : "app/build/dev/index.html"),
|
||||
pathname: indexPath,
|
||||
protocol: "file:",
|
||||
slashes: true
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,9 +34,12 @@
|
|||
"karma-chai": "^0.1.0",
|
||||
"karma-chrome-launcher": "^2.1.1",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"merge-stream": "^1.0.1",
|
||||
"mocha": "^3.4.2",
|
||||
"polymer-analyzer": "^2.2.0",
|
||||
"polymer-build": "^3.0.1",
|
||||
"polymer-bundler": "^2.3.1",
|
||||
"polymer-cli": "^1.7.2",
|
||||
"prettier": "^1.13.4",
|
||||
"rimraf": "^2.5.4",
|
||||
"st": "^1.2.0",
|
||||
|
@ -57,7 +60,9 @@
|
|||
"browser": "cd app && polymer serve --open",
|
||||
"lint": "eslint app/**/*.js && prettier --list-different 'app/src/**/*.{js,ts}'",
|
||||
"test": "karma start --single-run --browsers ChromeHeadless karma.conf.js",
|
||||
"app": "electron .",
|
||||
"app": "npm run build:electron && electron . --dir app/build/electron",
|
||||
"build:electron": "cd app && polymer build --name electron --js-compile --bundle --js-transform-modules-to-amd && cd ..",
|
||||
"build:pwa": "cd app && polymer build --name pwa --add-service-worker",
|
||||
"build:mac": "gulp build --mac --silent",
|
||||
"build:win": "gulp build --win --silent",
|
||||
"build:linux": "gulp build --linux --silent",
|
||||
|
|
Loading…
Reference in New Issue