Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate API service, deploy frontend statically #474

Merged
merged 4 commits into from
Aug 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
.env
.next
out
cypress/videos
cypress/screenshots
.idea
Expand Down
47 changes: 11 additions & 36 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,38 +1,13 @@
FROM node:9-alpine

# Source https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
# Installs latest Chromium package.
ENV CHROME_BIN=/usr/bin/chromium-browser
RUN apk update && apk upgrade && \
echo http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
echo http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
apk add --no-cache \
chromium \
nss

WORKDIR /app

COPY package.json ./
COPY yarn.lock ./

# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true

# Source: https://github.com/zeit/now-static-build-starter/blob/master/Dockerfile
FROM mhart/alpine-node:10
# We store all our files in /usr/src to perform the build
WORKDIR /usr/src
# We first add only the files required for installing deps
# If package.json or yarn.lock don't change, no need to re-install later
COPY package.json yarn.lock ./
# We install our deps
RUN yarn

# We copy all source files
COPY . .

RUN yarn build

# Add user so we don't need --no-sandbox.
RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /app

# Run everything after as non-privileged user.
USER pptruser

ENV NODE_ENV production
EXPOSE 3000
CMD [ "yarn", "start" ]
# We run the build and expose as /public
RUN yarn build && yarn export -o /public
36 changes: 36 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM node:9-alpine

# Source https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
# Installs latest Chromium package.
ENV CHROME_BIN=/usr/bin/chromium-browser
RUN apk update && apk upgrade && \
echo http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
echo http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
apk add --no-cache \
chromium \
nss

WORKDIR /app

COPY package.json ./
COPY yarn.lock ./

# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true

RUN yarn

COPY . .

# Add user so we don't need --no-sandbox.
RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /app

# Run everything after as non-privileged user.
USER pptruser

ENV NODE_ENV production
EXPOSE 4000
CMD [ "node", "server.js" ]
File renamed without changes.
5 changes: 2 additions & 3 deletions handlers/image.js → api/handlers/image.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* global domtoimage */
const PORT = parseInt(process.env.PORT, 10) || 3000
const ARBITRARY_WAIT_TIME = 500

module.exports = browser => async (req, res) => {
Expand All @@ -9,8 +8,8 @@ module.exports = browser => async (req, res) => {
if (!state) res.status(400).send()

try {
await page.goto(`http://localhost:${PORT}?state=${state}`)
await page.addScriptTag({ path: './lib/customDomToImage.js' })
await page.goto(`http://carbon.now.sh?state=${state}`)
await page.addScriptTag({ path: './customDomToImage.js' })

// wait for page to detect language
await delay(ARBITRARY_WAIT_TIME)
Expand Down
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions api/now.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "carbon-api",
"alias": "carbon-api.now.sh",
"type": "docker",
"public": true,
"env": {
"NODE_ENV": "production",
"TWITTER_CONSUMER_KEY": "@twitter-consumer-key",
"TWITTER_CONSUMER_SECRET": "@twitter-consumer-secret",
"TWITTER_ACCESS_TOKEN_KEY": "@twitter-access-token-key",
"TWITTER_ACCESS_TOKEN_SECRET": "@twitter-access-token-secret",
"LOGS_SECRET_PREFIX": "@logs_secret_prefix",
"UNSPLASH_SECRET_KEY": "@unsplash_secret_key",
"UNSPLASH_ACCESS_KEY": "@unsplash_access_key",
"UNSPLASH_CALLBACK_URL": "@unsplash_callback_url"
},
"features": {
"cloud": "v1"
}
}
24 changes: 24 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "carbon-api",
"version": "0.0.0-semantically-released",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "node server.js",
"start": "node server.js",
"deploy": "now"
},
"dependencies": {
"body-parser": "^1.17.2",
"compression": "^1.7.3",
"cors": "^2.8.4",
"express": "^4.16.2",
"isomorphic-fetch": "^2.2.1",
"morgan": "^1.8.2",
"morphmorph": "^0.1.2",
"now-logs": "^0.0.7",
"puppeteer": "1.7.0",
"twit": "^2.2.9",
"unsplash-js": "^4.8.0"
}
}
63 changes: 63 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const express = require('express')
const cors = require('cors')
const compression = require('compression')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const puppeteer = require('puppeteer')

const port = parseInt(process.env.PORT, 10) || 4000
const dev = process.env.NODE_ENV !== 'production'

process.on('SIGINT', process.exit)

if (!dev) {
const LOGS_ID = `${process.env.LOGS_SECRET_PREFIX}:${process.env.NOW_URL}`
require('now-logs')(LOGS_ID)
}

function wrap(handler) {
return (req, res) =>
handler(req, res).catch(err => {
// eslint-disable-next-line
console.log('ERR:', err)
res.status(400).end()
})
}

const puppeteerParams = dev
? {}
: {
executablePath: '/usr/bin/chromium-browser',
args: ['--no-sandbox', '--disable-setuid-sandbox']
}

puppeteer.launch(puppeteerParams).then(browser => {
// set up
const server = express()
const imageHandler = require('./handlers/image')(browser)
const unsplashHandler = require('./handlers/unsplash')

if (dev) {
server.use(morgan('tiny'))
}

server.use(cors())

server.use(compression())

// Service Worker
// const filePath = path.join(__dirname, '.next', 'service-worker.js')
// server.get('/service-worker.js', (req, res) => app.serveStatic(req, res, filePath))

// api endpoints
server.post('/twitter', bodyParser.json({ limit: '5mb' }), require('./handlers/twitter'))
server.post('/image', bodyParser.json({ limit: '5mb' }), wrap(imageHandler))
server.get('/unsplash/random', wrap(unsplashHandler.randomImages))
server.get('/unsplash/download/:imageId', wrap(unsplashHandler.downloadImage))

server.listen(port, '0.0.0.0', err => {
if (err) throw err
// eslint-disable-next-line
console.log(`> Ready on http://localhost:${port}`)
})
})
Loading