[next] Production Usage (#1808)

* feat: docker + compression support + headers

* fixed bug with dependancies
This commit is contained in:
Wyatt Johnson
2018-09-04 18:36:17 +00:00
committed by GitHub
parent bcf24cbb4b
commit 76d198f2a6
8 changed files with 140 additions and 14 deletions
+30
View File
@@ -0,0 +1,30 @@
# excluded because we'll likely need to rebuild this.
node_modules
# static assets are rebuild in the docker container.
dist
# tests are not run in the docker container.
__tests__
# we won't use the .git folder in production.
.git
# hide the environment config.
.env
# don't include logs.
npm-debug.log*
yarn-error.log
# hide OS specific files.
.idea/
.vs
.docz
*.swp
*.DS_STORE
# hide generated files.
*.css.d.ts
__generated__
+41
View File
@@ -0,0 +1,41 @@
FROM node:8-alpine
# Install installation dependancies.
RUN apk --no-cache add git
# Create app directory.
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Setup the environment for production.
ENV NODE_ENV production
# Bundle application source.
COPY . /usr/src/app
# Install build static assets and clear caches.
RUN NODE_ENV=development npm install && \
npm run compile && \
npm run build && \
npm prune --production
FROM node:8-alpine
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Copy the compiled source into the new stage.
COPY --from=0 /usr/src/app .
# Setup the environment
ENV PATH /usr/src/app/bin:$PATH
ENV PORT 5000
EXPOSE 5000
ENV NODE_ENV production
# Store the current git revision.
ARG REVISION_HASH
ENV REVISION_HASH=${REVISION_HASH}
CMD ["npm", "run", "start"]
+27 -10
View File
@@ -1690,6 +1690,15 @@
"commander": "*"
}
},
"@types/compression-webpack-plugin": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@types/compression-webpack-plugin/-/compression-webpack-plugin-0.4.2.tgz",
"integrity": "sha512-kAjvB1XBtGx7xBKiDTqQDE/zldh0LTroHeyK0p7Jogc/ggRYdPTDoyKhcAzK8RLCsGcVHAlOXLhN8gbfL93JhA==",
"dev": true,
"requires": {
"@types/webpack": "*"
}
},
"@types/connect": {
"version": "3.4.32",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
@@ -6482,6 +6491,19 @@
"vary": "~1.1.2"
}
},
"compression-webpack-plugin": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-1.1.11.tgz",
"integrity": "sha512-ZVWKrTQhtOP7rDx3M/koXTnRm/iwcYbuCdV+i4lZfAIe32Mov7vUVM0+8Vpz4q0xH+TBUZxq+rM8nhtkDH50YQ==",
"dev": true,
"requires": {
"cacache": "^10.0.1",
"find-cache-dir": "^1.0.0",
"neo-async": "^2.5.0",
"serialize-javascript": "^1.4.0",
"webpack-sources": "^1.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -10129,8 +10151,11 @@
"resolved": "https://registry.npmjs.org/fluent-intl-polyfill/-/fluent-intl-polyfill-0.1.0.tgz",
"integrity": "sha1-ETOUSrJHeINHOZVZaIPg05z4hc8=",
"dev": true,
"requires": {
"intl-pluralrules": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b"
"dependencies": {
"intl-pluralrules": {
"version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b",
"from": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b"
}
}
},
"fluent-langneg": {
@@ -11295,7 +11320,6 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/graphql-playground-html/-/graphql-playground-html-1.6.0.tgz",
"integrity": "sha512-et3huQFEuAZgAiUfs9a+1Wo/JDX94k7XqNRc8LhpGT8k2NwIhMAbZKqudVF/Ww4+XDoEB4LUTSFGRPBYvKrcKQ==",
"dev": true,
"requires": {
"graphql-config": "2.0.0"
},
@@ -11304,7 +11328,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-2.0.0.tgz",
"integrity": "sha512-//hZmROEk79zzPlH6SVTQeXd8NVV65rquz1zxZeO6oEuX5KNnii8+oznLu7d897EfJ+NShTZtsY9FMmxxkWmJw==",
"dev": true,
"requires": {
"graphql-import": "^0.4.0",
"graphql-request": "^1.4.0",
@@ -11319,7 +11342,6 @@
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/graphql-playground-middleware-express/-/graphql-playground-middleware-express-1.7.2.tgz",
"integrity": "sha512-JvKsVOR/U5QguBtEvTt0ozQ49uh1C6cW8O1xR6krQpJZIxjLYqpgusLUddTiVkka6Q/A4/AXBohY85jPudxYDg==",
"dev": true,
"requires": {
"graphql-playground-html": "1.6.0"
}
@@ -12545,11 +12567,6 @@
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
"dev": true
},
"intl-pluralrules": {
"version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b",
"from": "github:projectfluent/IntlPluralRules#module",
"dev": true
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+3 -1
View File
@@ -47,6 +47,7 @@
"fs-extra": "^6.0.1",
"graphql": "^0.13.2",
"graphql-config": "^2.0.1",
"graphql-playground-middleware-express": "^1.7.2",
"graphql-redis-subscriptions": "^1.5.0",
"graphql-tools": "^3.0.5",
"ioredis": "^3.2.2",
@@ -83,6 +84,7 @@
"@types/chokidar": "^1.7.5",
"@types/classnames": "^2.2.4",
"@types/commander": "^2.12.2",
"@types/compression-webpack-plugin": "^0.4.2",
"@types/consolidate": "0.0.34",
"@types/convict": "^4.2.0",
"@types/cross-spawn": "^6.0.0",
@@ -143,6 +145,7 @@
"classnames": "^2.2.5",
"commander": "^2.16.0",
"comment-json": "^1.1.3",
"compression-webpack-plugin": "^1.1.11",
"copy-webpack-plugin": "^4.5.1",
"cross-spawn": "^6.0.5",
"css-loader": "^0.28.11",
@@ -159,7 +162,6 @@
"fluent-intl-polyfill": "^0.1.0",
"fluent-langneg": "^0.1.0",
"fluent-react": "^0.8.0",
"graphql-playground-middleware-express": "^1.7.2",
"graphql-schema-typescript": "^1.2.1",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0-beta.2",
+3
View File
@@ -1,4 +1,5 @@
import CaseSensitivePathsPlugin from "case-sensitive-paths-webpack-plugin";
import CompressionPlugin from "compression-webpack-plugin";
import HtmlWebpackPlugin, { Options } from "html-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import path from "path";
@@ -111,6 +112,8 @@ export default function createWebpackConfig({
filename: "assets/css/[name].[hash].css",
chunkFilename: "assets/css/[id].[hash].css",
}),
// Pre-compress all the assets as they will be served as is.
new CompressionPlugin({}),
]
: [
// Add module names to factory functions so they appear in browser profiler.
+3 -1
View File
@@ -14,6 +14,7 @@ import { handleSubscriptions } from "talk-server/graph/common/subscriptions/midd
import { Schemas } from "talk-server/graph/schemas";
import TenantCache from "talk-server/services/tenant/cache";
import { cacheHeadersMiddleware } from "talk-server/app/middleware/cacheHeaders";
import { errorHandler } from "talk-server/app/middleware/error";
import { accessLogger, errorLogger } from "./middleware/logging";
import serveStatic from "./middleware/serveStatic";
@@ -47,13 +48,14 @@ export async function createApp(options: AppOptions): Promise<Express> {
// Mount the router.
parent.use(
"/",
await createRouter(options, {
passport,
})
);
// Static Files
parent.use("/assets", serveStatic);
parent.use("/assets", cacheHeadersMiddleware("1w"), serveStatic);
// Error Handling
parent.use(notFoundMiddleware);
@@ -0,0 +1,27 @@
import { RequestHandler } from "express";
import ms from "ms";
export const nocacheMiddleware: RequestHandler = (req, res, next) => {
// Set cache control headers to prevent browsers/cdn's from caching these
// requests.
res.set({ "Cache-Control": "no-cache, no-store, must-revalidate" });
next();
};
export const cacheHeadersMiddleware = (duration: string): RequestHandler => {
const maxAge = duration ? Math.floor(ms(duration) / 1000) : false;
if (!maxAge) {
return nocacheMiddleware;
}
return (req, res, next) => {
// Set cache control headers to encourage browsers/cdn's to cache these
// requests if we aren't in private mode.
res.set({
"Cache-Control": `public, max-age=${maxAge}`,
});
next();
};
};
+6 -2
View File
@@ -13,6 +13,10 @@ import tenantMiddleware from "talk-server/app/middleware/tenant";
import managementGraphMiddleware from "talk-server/graph/management/middleware";
import tenantGraphMiddleware from "talk-server/graph/tenant/middleware";
import {
cacheHeadersMiddleware,
nocacheMiddleware,
} from "talk-server/app/middleware/cacheHeaders";
import { AppOptions } from "./index";
import playground from "./middleware/playground";
@@ -123,7 +127,7 @@ export async function createRouter(app: AppOptions, options: RouterOptions) {
// Create a router.
const router = express.Router();
router.use("/api", await createAPIRouter(app, options));
router.use("/api", nocacheMiddleware, await createAPIRouter(app, options));
if (app.config.get("env") === "development") {
// Tenant GraphiQL
@@ -146,7 +150,7 @@ export async function createRouter(app: AppOptions, options: RouterOptions) {
}
// Handle the stream handler.
router.get("/embed/stream", streamHandler);
router.get("/embed/stream", cacheHeadersMiddleware("1h"), streamHandler);
return router;
}