diff --git a/Dockerfile b/Dockerfile index dfedbba36c3..59c309a0099 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ -FROM node:10-alpine as builder -LABEL maintainer="Niranjan Rajendran " +FROM node:12-alpine as builder WORKDIR /app @@ -25,16 +24,18 @@ FROM node:10-alpine WORKDIR /fastboot -COPY scripts/fastboot-server.js . -COPY --from=builder /app/dist/ app/ +COPY --from=builder /app/dist/ dist/ RUN apk add --no-cache ca-certificates && \ - cp app/package.json . && \ + cp dist/package.json . && \ yarn install && \ - yarn add fastboot-app-server && \ + yarn add fastboot-app-server dotenv lodash safe-eval && \ rm -rf yarn.lock && \ yarn cache clean +COPY scripts/* ./scripts/ +COPY config/environment.js ./config/ + EXPOSE 4000 -CMD ["node", "fastboot-server.js"] +CMD ["node", "./scripts/fastboot-server.js"] diff --git a/scripts/fastboot-server.js b/scripts/fastboot-server.js index b0826e7edfc..1f0c9e13ade 100644 --- a/scripts/fastboot-server.js +++ b/scripts/fastboot-server.js @@ -1,7 +1,10 @@ +require('dotenv').config() + const FastBootAppServer = require('fastboot-app-server'); +const { injectEnvironment } = require('./replace-config'); const enableGzip = process.env.FASTBOOT_GZIP || 'true'; -const fastbootDistPath = process.env.FASTBOOT_DIST_PATH || '/fastboot/app'; +const fastbootDistPath = process.env.FASTBOOT_DIST_PATH || './dist'; const enableChunkedResponse = process.env.FASTBOOT_CHUNKED_RESPONSE || 'true'; const fastbootHost = process.env.FASTBOOT_HOST || '0.0.0.0'; const fastbootPort = process.env.FASTBOOT_PORT || process.env.PORT || '4000'; @@ -16,4 +19,10 @@ let fastbootServer = new FastBootAppServer({ workerCount : parseInt(fastbootWorkers) }); -fastbootServer.start(); +(async () => { + if (process.env.INJECT_ENV === 'true') { + await injectEnvironment(); + } + + fastbootServer.start(); +})(); diff --git a/scripts/replace-config.js b/scripts/replace-config.js new file mode 100644 index 00000000000..997586e25d7 --- /dev/null +++ b/scripts/replace-config.js @@ -0,0 +1,132 @@ +require('dotenv').config() + +const fs = require('fs'); +const promisify = require('util').promisify +const { merge } = require('lodash') +const safeEval = require('safe-eval') + +const env = require('../config/environment') +const appName = 'open-event-frontend' + +const environment = env('production') + +async function replaceFastbootConfig() { + const packagePath = './dist/package.json' + const packageInfo = require('.' + packagePath) + + const old = packageInfo.fastboot.config[appName] + packageInfo.fastboot.config[appName] = merge(old, environment); + await promisify(fs.writeFile)(packagePath, JSON.stringify(packageInfo)) + + console.log('Transformed package.json with new environment') +} + +function findObject(js, objectStart) { + let braceCount = 1; + + const start = js.indexOf("{", objectStart); + + if (start < 0) { + return null; + } + + let index = start + 1; + let parseBlocker = null; + let parseBlockerBuffer = null; + + while (index < js.length) { + const c = js[index]; + + if (!parseBlocker && !parseBlockerBuffer) { + if (c == "{") { + braceCount += 1; + } else if (c == "}") { + braceCount -= 1; + } else if (c === '"' || c === "'" || c === "`") { + parseBlocker = c; + } else if (js[index - 1] == "/") { + if (c == "/") parseBlocker = "\n"; + else if (c == "*") parseBlockerBuffer = "*/"; + } + + if (braceCount === 0) { + break; + } + } else { + if (c === parseBlocker) { + parseBlocker = null; + } else if (c == '/' && js[index - 1] == '*') { + parseBlockerBuffer = null; + } + } + + index++; + } + + if (index >= js.length) return null; + + return { + start, + end: index + }; +} + +function replace(str, start, end, replacement) { + return str.substring(0, start) + replacement + str.substring(end + 1, str.length) +} + +async function replaceWebConfig() { + const pattern = new RegExp(`^${appName}.*\.js$`) + const basePath = './dist/assets/' + const appJs = (await promisify(fs.readdir)(basePath)).filter(name => name.match(pattern)) + + const envDefinition = 'define("open-event-frontend/config/environment"' + + for (const js of appJs) { + const jsPath = basePath + js; + const code = (await promisify(fs.readFile)(jsPath)).toString() + let defineIndex = code.indexOf(envDefinition) + + if (defineIndex < 0) { + defineIndex = code.indexOf(envDefinition.replace(/"/g, "'")) + if (defineIndex < 0) + continue; + } + + const defaultIndex = code.indexOf('default', defineIndex + 1) + + if (defaultIndex < 0) + continue; + + // File with environment definition found + + console.log('Transforming ' + js) + + const object = findObject(code, defaultIndex) + + console.log('Environment Object Found', object) + + const webEnvJson = code.substring(object.start, object.end + 1) + const old = safeEval('(' + webEnvJson + ')') + + const newEnv = JSON.stringify(merge(old, environment)) + const newCode = replace(code, object.start, object.end, newEnv) + + console.log('Injected new environment') + + await promisify(fs.writeFile)(jsPath, newCode) + + console.log('Transformation Complete') + + break; + } +} + +async function injectEnvironment() { + await replaceFastbootConfig() + await replaceWebConfig() +} + +module.exports = { + injectEnvironment +}