diff options
| author | Shyam Sunder <sgsunder1@gmail.com> | 2018-09-03 17:36:06 -0400 |
|---|---|---|
| committer | rr- <rr-@sakuya.pl> | 2018-12-22 12:31:25 +0100 |
| commit | a5a06bf2d10b2a2e16ae3e91cf119c56cb050532 (patch) | |
| tree | 6f8d261352e9d287125445155cf3de9cb0312a77 /client | |
| parent | e6445b431f9f155b4511d8ceeffaf3a3fded425b (diff) | |
client/build: Clean up build process
Fixes incorrect URIs of iOS splash screens and OpenSans font
Files get gzipped inside build script
Better nginx configuration
build.js uses more consistent, synchronous code
Diffstat (limited to 'client')
| -rw-r--r-- | client/Dockerfile | 7 | ||||
| -rwxr-xr-x[-rw-r--r--] | client/build.js | 357 | ||||
| -rw-r--r-- | client/css/core-general.styl | 2 | ||||
| -rw-r--r-- | client/nginx.conf.docker | 2 |
4 files changed, 197 insertions, 171 deletions
diff --git a/client/Dockerfile b/client/Dockerfile index 69555a4..a3d0ffc 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -8,10 +8,7 @@ COPY . ./ ARG BUILD_INFO="docker-latest" ARG CLIENT_BUILD_ARGS="" -RUN BASE_URL="__BASEURL__" node build.js ${CLIENT_BUILD_ARGS} - -RUN find public/ -name public/index.html -prune -o -type f -size +5k \ - -print0 | xargs -0 -- gzip -6 -k +RUN BASE_URL="__BASEURL__" node build.js --gzip ${CLIENT_BUILD_ARGS} FROM nginx:alpine @@ -23,7 +20,7 @@ RUN \ echo 'sed -i "s|__BACKEND__|${BACKEND_HOST}|" /etc/nginx/nginx.conf' \ >> /init && \ echo 'sed -i "s|__BASEURL__|${BASE_URL:-/}|" /var/www/index.htm' >> /init && \ - echo 'exec nginx -g "daemon off;"' >> /init && \ + echo 'exec nginx' >> /init && \ chmod a+x /init CMD ["/init"] diff --git a/client/build.js b/client/build.js index fdc5fd0..dd63a5f 100644..100755 --- a/client/build.js +++ b/client/build.js @@ -1,5 +1,35 @@ +#!/usr/bin/env node 'use strict'; +// ------------------------------------------------- + +const webapp_icons = [ + {name: 'android-chrome-192x192.png', size: 192}, + {name: 'android-chrome-512x512.png', size: 512}, + {name: 'apple-touch-icon.png', size: 180}, + {name: 'mstile-150x150.png', size: 150} +]; + +const webapp_splash_screens = [ + {w: 640, h: 1136, center: 320}, + {w: 750, h: 1294, center: 375}, + {w: 1125, h: 2436, center: 565}, + {w: 1242, h: 2148, center: 625}, + {w: 1536, h: 2048, center: 770}, + {w: 1668, h: 2224, center: 820}, + {w: 2048, h: 2732, center: 1024} +]; + +const external_js = [ + 'underscore', + 'superagent', + 'mousetrap', + 'js-cookie', + 'nprogress', +]; + +// ------------------------------------------------- + const fs = require('fs'); const glob = require('glob'); const path = require('path'); @@ -10,227 +40,224 @@ function readTextFile(path) { return fs.readFileSync(path, 'utf-8'); } -function writeFile(path, content) { - return fs.writeFileSync(path, content); +function gzipFile(file) { + file = path.normalize(file); + execSync('gzip -6 -k ' + file); } -function getVersion() { - let build_info = process.env.BUILD_INFO; - if (build_info) { - return build_info.trim(); - } else { - try { - build_info = execSync('git describe --always --dirty --long --tags') - .toString(); - } catch (e) { - console.warn('Cannot find build version'); - return 'unknown'; - } - return build_info.trim(); - } -} +// ------------------------------------------------- -function getConfig() { - let config = { - meta: { - version: getVersion(), - buildDate: new Date().toUTCString() - } - }; +function bundleHtml() { + const underscore = require('underscore'); + const babelify = require('babelify'); - return config; -} + const baseUrl = process.env.BASE_URL ? process.env.BASE_URL : '/'; -function copyFile(source, target) { - fs.createReadStream(source).pipe(fs.createWriteStream(target)); -} + function minifyHtml(html) { + return require('html-minifier').minify(html, { + removeComments: true, + collapseWhitespace: true, + conservativeCollapse: true, + }).trim(); + } -function minifyJs(path) { - return require('terser').minify(fs.readFileSync(path, 'utf-8'), {compress: {unused: false}}).code; -} + const baseHtml = readTextFile('./html/index.htm') + .replace('<!-- Base HTML Placeholder -->', `<base href="${baseUrl}"/>`); + fs.writeFileSync('./public/index.htm', minifyHtml(baseHtml)); -function minifyCss(css) { - return require('csso').minify(css).css; -} + let compiledTemplateJs = [ + `'use strict';`, + `let _ = require('underscore');`, + `let templates = {};` + ]; -function minifyHtml(html) { - return require('html-minifier').minify(html, { - removeComments: true, - collapseWhitespace: true, - conservativeCollapse: true, - }).trim(); -} + for (const file of glob.sync('./html/**/*.tpl')) { + const name = path.basename(file, '.tpl').replace(/_/g, '-'); + const placeholders = []; + let templateText = readTextFile(file); + templateText = templateText.replace( + /<%.*?%>/ig, + (match) => { + const ret = '%%%TEMPLATE' + placeholders.length; + placeholders.push(match); + return ret; + }); + templateText = minifyHtml(templateText); + templateText = templateText.replace( + /%%%TEMPLATE(\d+)/g, + (match, number) => { return placeholders[number]; }); -function bundleHtml() { - const underscore = require('underscore'); - const babelify = require('babelify'); - const baseHtml = readTextFile('./html/index.htm', 'utf-8'); - const baseUrl = process.env.BASE_URL ? process.env.BASE_URL : '/'; - const finalHtml = baseHtml.replace( - '<!-- Base HTML Placeholder -->', `<base href="${baseUrl}"/>`); - writeFile('./public/index.htm', minifyHtml(finalHtml)); + const functionText = underscore.template( + templateText, {variable: 'ctx'}).source; - glob('./html/**/*.tpl', {}, (er, files) => { - let compiledTemplateJs = '\'use strict\'\n'; - compiledTemplateJs += 'let _ = require(\'underscore\');'; - compiledTemplateJs += 'let templates = {};'; - for (const file of files) { - const name = path.basename(file, '.tpl').replace(/_/g, '-'); - const placeholders = []; - let templateText = readTextFile(file, 'utf-8'); - templateText = templateText.replace( - /<%.*?%>/ig, - (match) => { - const ret = '%%%TEMPLATE' + placeholders.length; - placeholders.push(match); - return ret; - }); - templateText = minifyHtml(templateText); - templateText = templateText.replace( - /%%%TEMPLATE(\d+)/g, - (match, number) => { return placeholders[number]; }); + compiledTemplateJs.push(`templates['${name}'] = ${functionText};`); + } + compiledTemplateJs.push('module.exports = templates;'); - const functionText = underscore.template( - templateText, {variable: 'ctx'}).source; - compiledTemplateJs += `templates['${name}'] = ${functionText};`; - } - compiledTemplateJs += 'module.exports = templates;'; - writeFile('./js/.templates.autogen.js', compiledTemplateJs); - console.info('Bundled HTML'); - }); + fs.writeFileSync('./js/.templates.autogen.js', compiledTemplateJs.join('\n')); + console.info('Bundled HTML'); } function bundleCss() { const stylus = require('stylus'); - glob('./css/**/*.styl', {}, (er, files) => { - let css = ''; - for (const file of files) { - css += stylus.render( - readTextFile(file), {filename: file}); - } - writeFile('./public/css/app.min.css', minifyCss(css)); - copyFile( - './node_modules/font-awesome/css/font-awesome.min.css', - './public/css/vendor.min.css'); + function minifyCss(css) { + return require('csso').minify(css).css; + } + + let css = ''; + for (const file of glob.sync('./css/**/*.styl')) { + css += stylus.render(readTextFile(file), {filename: file}); + } + fs.writeFileSync('./public/css/app.min.css', minifyCss(css)); + if (process.argv.includes('--gzip')) { + gzipFile('./public/css/app.min.css'); + } - console.info('Bundled CSS'); - }); + fs.copyFileSync( + './node_modules/font-awesome/css/font-awesome.min.css', + './public/css/vendor.min.css'); + if (process.argv.includes('--gzip')) { + gzipFile('./public/css/vendor.min.css'); + } + + console.info('Bundled CSS'); } function bundleJs() { const browserify = require('browserify'); - const external = [ - 'underscore', - 'superagent', - 'mousetrap', - 'js-cookie', - 'nprogress', - ]; - function writeJsBundle(b, path, message, compress) { + function minifyJs(path) { + return require('terser').minify( + fs.readFileSync(path, 'utf-8'), {compress: {unused: false}}).code; + } + + function writeJsBundle(b, path, compress, callback) { let outputFile = fs.createWriteStream(path); b.bundle().pipe(outputFile); - outputFile.on('finish', function() { + outputFile.on('finish', () => { if (compress) { - writeFile(path, minifyJs(path)); + fs.writeFileSync(path, minifyJs(path)); } - console.info(message); + callback(); }); } - glob('./js/**/*.js', {}, (er, files) => { - if (!process.argv.includes('--no-vendor-js')) { - let b = browserify(); - for (let lib of external) { - b.require(lib); - } - if (!process.argv.includes('--no-transpile')) { - b.add(require.resolve('babel-polyfill')); + if (!process.argv.includes('--no-vendor-js')) { + let b = browserify(); + for (let lib of external_js) { + b.require(lib); + } + if (!process.argv.includes('--no-transpile')) { + b.add(require.resolve('babel-polyfill')); + } + const file = './public/js/vendor.min.js'; + writeJsBundle(b, file, true, () => { + if (process.argv.includes('--gzip')) { + gzipFile(file); } - writeJsBundle( - b, './public/js/vendor.min.js', 'Bundled vendor JS', true); + console.info('Bundled vendor JS'); + }); + } + + if (!process.argv.includes('--no-app-js')) { + let b = browserify({debug: process.argv.includes('--debug')}); + if (!process.argv.includes('--no-transpile')) { + b = b.transform('babelify'); } + b = b.external(external_js).add(glob.sync('./js/**/*.js')); + const compress = !process.argv.includes('--debug'); + const file = './public/js/app.min.js'; + writeJsBundle(b, file, compress, () => { + if (process.argv.includes('--gzip')) { + gzipFile(file); + } + console.info('Bundled app JS'); + }); + } +} - if (!process.argv.includes('--no-app-js')) { - let outputFile = fs.createWriteStream('./public/js/app.min.js'); - let b = browserify({debug: process.argv.includes('--debug')}); - if (!process.argv.includes('--no-transpile')) { - b = b.transform('babelify'); +function bundleConfig() { + function getVersion() { + let build_info = process.env.BUILD_INFO; + if (!build_info) { + try { + build_info = execSync('git describe --always --dirty --long --tags').toString(); + } catch (e) { + console.warn('Cannot find build version'); + build_info = 'unknown'; } - writeJsBundle( - b.external(external).add(files), - './public/js/app.min.js', - 'Bundled app JS', - !process.argv.includes('--debug')); } - }); + return build_info.trim(); + } + const config = { + meta: { + version: getVersion(), + buildDate: new Date().toUTCString() + } + }; + + fs.writeFileSync('./js/.config.autogen.json', JSON.stringify(config)); } -function bundleConfig(config) { - writeFile( - './js/.config.autogen.json', JSON.stringify(config)); - glob('./node_modules/font-awesome/fonts/*.*', {}, (er, files) => { - for (let file of files) { - if (fs.lstatSync(file).isDirectory()) { +function bundleBinaryAssets() { + fs.copyFileSync('./img/favicon.png', './public/img/favicon.png'); + fs.copyFileSync('./img/transparency_grid.png', './public/img/transparency_grid.png'); + + for (let file of glob.sync('./node_modules/font-awesome/fonts/*.*')) { + if (fs.lstatSync(file).isDirectory()) { + continue; + } + fs.copyFileSync(file, path.join('./public/fonts/', path.basename(file))); + } + if (process.argv.includes('--gzip')) { + for (let file of glob.sync('./public/fonts/*.*')) { + if (file.endsWith('woff2')) { continue; } - copyFile(file, path.join('./public/fonts/', path.basename(file))); + gzipFile(file); } - }); + } + console.info('Copied Fonts') } -function bundleBinaryAssets() { - copyFile('./img/favicon.png', './public/img/favicon.png'); - copyFile('./img/transparency_grid.png', './public/img/transparency_grid.png'); - +function bundleWebAppFiles() { const Jimp = require('jimp'); - for (let icon of [ - {name: 'android-chrome-192x192.png', size: 192}, - {name: 'android-chrome-512x512.png', size: 512}, - {name: 'apple-touch-icon.png', size: 180}, - {name: 'mstile-150x150.png', size: 150} - ]) { - Jimp.read('./img/app.png', (err, infile) => { - infile - .resize(icon.size, Jimp.AUTO, Jimp.RESIZE_BEZIER) + fs.copyFileSync('./app/manifest.json', './public/manifest.json'); + + Promise.all(webapp_icons.map(icon => { + return Jimp.read('./img/app.png') + .then(file => { + file.resize(icon.size, Jimp.AUTO, Jimp.RESIZE_BEZIER) .write(path.join('./public/img/', icon.name)); }); - } - console.info('Generated webapp icons'); + })) + .then(() => { + console.info('Generated webapp icons'); + }); - for (let dim of [ - {w: 640, h: 1136, center: 320}, - {w: 750, h: 1294, center: 375}, - {w: 1125, h: 2436, center: 565}, - {w: 1242, h: 2148, center: 625}, - {w: 1536, h: 2048, center: 770}, - {w: 1668, h: 2224, center: 820}, - {w: 2048, h: 2732, center: 1024} - ]) { - Jimp.read('./img/splash.png', (err, infile) => { - infile - .resize(dim.center, Jimp.AUTO, Jimp.RESIZE_BEZIER) + Promise.all(webapp_splash_screens.map(dim => { + return Jimp.read('./img/splash.png') + .then(file => { + file.resize(dim.center, Jimp.AUTO, Jimp.RESIZE_BEZIER) .background(0xFFFFFFFF) .contain(dim.w, dim.center, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE) .contain(dim.w, dim.h, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE) .write(path.join('./public/img/', - 'apple-touch-startup-image-' - + dim.w + '-' + dim.h + '.png')); + 'apple-touch-startup-image-' + dim.w + 'x' + dim.h + '.png')); }); - } - console.info('Generated splash screens'); + })) + .then(() => { + console.info('Generated splash screens'); + }); } -function bundleWebAppFiles() { - copyFile('./app/manifest.json', './public/manifest.json'); -} +// ------------------------------------------------- -const config = getConfig(); -bundleConfig(config); +bundleConfig(); bundleBinaryAssets(); bundleWebAppFiles(); if (!process.argv.includes('--no-html')) { diff --git a/client/css/core-general.styl b/client/css/core-general.styl index f6d1382..df30782 100644 --- a/client/css/core-general.styl +++ b/client/css/core-general.styl @@ -6,7 +6,7 @@ font-family: 'Open Sans'; font-style: normal; font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(fonts/open_sans.woff2) format('woff2'); + src: local('Open Sans'), local('OpenSans'), url(../fonts/open_sans.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; /* make <body> cover entire viewport */ diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 6af4095..c9d77ea 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -1,4 +1,5 @@ worker_processes 1; +user nginx; error_log /dev/stderr warn; pid /var/run/nginx.pid; @@ -54,3 +55,4 @@ http { } } } +daemon off; |