mirror of
https://github.com/wassname/talk.git
synced 2026-06-27 18:07:26 +08:00
[next] Production Usage (#1808)
* feat: docker + compression support + headers * fixed bug with dependancies
This commit is contained in:
@@ -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
@@ -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"]
|
||||
Generated
+27
-10
@@ -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
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user