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

Bundle server code with webpack #578

Merged
merged 7 commits into from
Sep 9, 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
8 changes: 5 additions & 3 deletions deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ const { IS_PULL_REQUEST, BRANCH } = shelljs.env;

const isPullRequest = IS_PULL_REQUEST !== 'false';

const whitelistedBranches = ['master', 'beta', 'internal', 'materialize-more'];
const whitelistedBranches = ['master', 'beta', 'internal'];

async function main() {
const buildCommands = ['yarn test', 'yarn coverage/report', 'yarn build'];
const buildCommands = ['yarn test', 'yarn coverage/report'];
const deploymentCommands = [
'cp yarn.lock package.json ./dist && cd dist && yarn --prod',
`NODE_ENV=production serverless deploy --stage ${BRANCH} --aws-s3-accelerate`,
];

let isDeployment = false;
if (isPullRequest === true) {
console.info('Skipping deployment commands in PRs');
buildCommands.push(
`NODE_ENV=production serverless package --stage ${BRANCH}`,
);
} else if (!whitelistedBranches.includes(BRANCH)) {
console.info(
`Skipping deployment because the branch "${BRANCH}" is not whitelisted`,
Expand Down
14 changes: 5 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,16 @@
"server/check-ts": "tsc --project ./src --noEmit",
"app/check-ts": "tsc --project ./src/app --noEmit",
"check-ts": "npm-run-all -s copy-defs -p -c --aggregate-output '*/check-ts'",
"app/webpack/build": "NODE_ENV=production NO_PERF_CHECKS=1 webpack --config ./src/webpack/webpack.config.js",
"bundlesize": "bundlesize",
"copy-defs": "cp src/app/typings/fbSdk.d.ts src/typings",
"app/webpack/build": "NODE_ENV=production NO_PERF_CHECKS=1 webpack --config ./src/webpack/webpack.config.client.js",
"app/build": "API_ENDPOINT=${API_ENDPOINT:-https://api.hollowverse.com/graphql} run-s app/graphql/build app/webpack/build bundlesize",
"app/analyze": "webpack-bundle-analyzer dist/client/stats.json dist/client",
"app/graphql/schema": "apollo-codegen introspect-schema ${API_ENDPOINT:-https://api.hollowverse.com/graphql} --output ./graphqlSchema.json",
"app/graphql/types": "mkdir -p src/app/api && apollo-codegen generate --project-name app 'src/app/**/*.{graphql,gql}' --target typescript --output src/app/api/types.ts",
"app/graphql/dev": "nodemon -q --watch src/app --ext graphql,gql --exec 'run-s app/graphql/schema app/graphql/types'",
"app/graphql/build": "run-s app/graphql/schema app/graphql/types",
"server/app-server/dev": "API_ENDPOINT=${API_ENDPOINT:-https://api.hollowverse.com/graphql} APP_SERVER_PORT=${APP_SERVER_PORT:-3001} HOT=1 NODE_ENV=development webpack-dev-server --config ./src/webpack/webpack.config.js --host 0.0.0.0 --display-error-details --hot",
"server/app-server/start": "node dist/appServer.js",
"server/main-server/dev": "PORT=${PORT:-8081} API_ENDPOINT=${API_ENDPOINT:-https://api.hollowverse.com/graphql} nodemon -q --watch src --ignore src/app --ignore src/webpack --ext ts,tsx,json --exec 'node -r 'ts-node/register' src/mainServer.ts'",
"server/main-server/start": "node dist/mainServer.js",
"server/build": "tsc --project ./src && babel --config-file ./src/.babelrc ./dist -d dist",
"build": "npm-run-all -s clean server/build app/build",
"start": "NODE_ENV=production run-p server/main-server/start",
"server/app-server/dev": "API_ENDPOINT=${API_ENDPOINT:-https://api.hollowverse.com/graphql} APP_SERVER_PORT=${APP_SERVER_PORT:-3001} HOT=1 NODE_ENV=development webpack-dev-server --config ./src/webpack/webpack.config.client.js --host 0.0.0.0 --display-error-details --hot",
"dev": "NO_PROXY=${NO_PROXY:-1} NODE_ENV=development API_ENDPOINT=${API_ENDPOINT:-https://api.hollowverse.com/graphql} npm-run-all -s clean -p app/graphql/dev server/app-server/dev",
"clean/build": "del-cli './dist'",
"clean/test": "del-cli './coverage'",
Expand Down Expand Up @@ -221,12 +215,12 @@
"babel-minify-webpack-plugin": "^0.3.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-lodash": "^3.3.2",
"babel-plugin-module-resolver": "^3.1.1",
"babel-plugin-transform-inline-environment-variables": "^0.3.0",
"babel-preset-minify": "^0.4.0",
"bundlesize": "^0.15.3",
"circular-dependency-plugin": "^3.0.0",
"codecov": "^3.0.0",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^0.28.4",
"del-cli": "^1.1.0",
"eslint": "^4.19.1",
Expand Down Expand Up @@ -274,7 +268,9 @@
"serverless-apigw-binary": "^0.4.4",
"serverless-cloudfront-invalidate": "aghadiry/serverless-cloudfront-invalidate",
"serverless-content-encoding": "^1.0.20",
"serverless-plugin-scripts": "^1.0.2",
"serverless-plugin-typescript": "^1.1.5",
"serverless-webpack": "^5.2.0",
"source-map-loader": "^0.2.1",
"source-map-support": "^0.5.0",
"supertest": "^3.0.0",
Expand Down
25 changes: 15 additions & 10 deletions serverless.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
service: website

plugins:
- serverless-plugin-scripts
- serverless-webpack
- serverless-apigw-binary
- serverless-content-encoding
- serverless-cloudfront-invalidate

custom:
scripts:
hooks:
'before:package:createDeploymentArtifacts': yarn run-s copy-defs app/build

webpack:
packager: 'yarn'
webpackConfig: ./src/webpack/webpack.config.server.js
includeModules: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If webpack builds a single JS bundle, that includes all the dependencies, why do you need to includeModules?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there are still some packages not bundled with webpack due to incompatibilities. Those are defined in the externals field of the webpack config.


cloudfrontInvalidate:
distributionId: 'E3U55U3N2RXSA3'
items:
Expand Down Expand Up @@ -35,10 +46,10 @@ provider:
Action:
- secretsmanager:GetSecretValue
Resource:
- "${self:custom.secretsArnPrefix}/splunk/httpCollector/website/token-*"
- '${self:custom.secretsArnPrefix}/splunk/httpCollector/website/token-*'
functions:
servePages:
handler: dist/servePages.servePages
handler: src/servePages.servePages
events:
- http:
method: ANY
Expand All @@ -47,17 +58,11 @@ functions:
method: ANY
path: /{proxy+}
serveLogEndpoint:
handler: dist/serveLogEndpoint.serveLogEndpoint
handler: src/serveLogEndpoint.serveLogEndpoint
events:
- http:
method: POST
path: /log

package:
excludeDevDependencies: false
include:
- 'dist/**'
exclude:
- '**/*'


individually: true
14 changes: 0 additions & 14 deletions src/.babelrc

This file was deleted.

10 changes: 0 additions & 10 deletions src/app/typings/webpack-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,3 @@ declare module '*.html' {
const str: string;
export = str;
}

declare module '!!json-loader!*' {
const json: object;
export = json;
}

declare module 'json-loader!*' {
const json: object;
export = json;
}
37 changes: 8 additions & 29 deletions src/webpack/createBaseConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ const path = require('path');

const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const { URL } = require('url');

const { compact } = require('lodash');
const { compact, mapValues } = require('lodash');

const { srcDirectory, excludedPatterns, publicPath } = require('./variables');

const { isHot, isDev, isProd } = require('@hollowverse/utils/helpers/env');
const { isHot, isProd } = require('@hollowverse/utils/helpers/env');
const { getAppGlobals } = require('./appGlobals');

const { API_ENDPOINT = 'https://api.hollowverse.com/graphql' } = process.env;

Expand Down Expand Up @@ -39,30 +38,6 @@ module.exports.createBaseConfig = () => ({
stats: 'errors-only',
},

// See https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a
optimization: {
noEmitOnErrors: true,
// Required for debugging in development and for long-term caching in production
namedModules: true,
namedChunks: true,
minimizer: [
new UglifyJsPlugin({
parallel: true,
sourceMap: true,
uglifyOptions: {
comments: false,
minimize: true,
safari10: true, // Workaround Safari 10 bugs
compress: {
inline: false, // Buggy
},
},
}),
],
},

devtool: isDev ? 'cheap-module-source-map' : 'source-map',

module: {
rules: compact([
// Read source maps produced by TypeScript and Babel and merge
Expand Down Expand Up @@ -140,7 +115,7 @@ module.exports.createBaseConfig = () => ({

'es6-promise': 'empty-module',
},
extensions: ['.tsx', '.ts', '.js'],
extensions: ['.tsx', '.ts', '.js', '.json'],
modules: [
// Allow absolute imports from 'src' dir,
// e.g. `import 'file';` instead of `'../../file';`
Expand All @@ -163,5 +138,9 @@ module.exports.createBaseConfig = () => ({
]),

new SpriteLoaderPlugin(),

new webpack.DefinePlugin(
mapValues(getAppGlobals(), v => JSON.stringify(v)),
),
]),
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const { StatsWriterPlugin } = require('webpack-stats-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const path = require('path');
const { compact, mapValues } = require('lodash');
const { compact } = require('lodash');

const { createScriptRules } = require('./helpers');
const {
Expand All @@ -16,7 +16,6 @@ const {
publicPath,
} = require('./variables');
const { createBaseConfig } = require('./createBaseConfig');
const { getAppGlobals } = require('./appGlobals');

const common = createBaseConfig();

Expand All @@ -25,6 +24,7 @@ const {
ifDev,
ifPerf,
isProd,
isDev,
} = require('@hollowverse/utils/helpers/env');

const clientSpecificConfig = {
Expand All @@ -41,7 +41,27 @@ const clientSpecificConfig = {
publicPath,
},

// See https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a
optimization: {
noEmitOnErrors: true,
// Required for debugging in development and for long-term caching in production
namedModules: true,
namedChunks: true,
minimizer: [
new UglifyJsPlugin({
parallel: true,
sourceMap: true,
uglifyOptions: {
comments: false,
minimize: true,
safari10: true, // Workaround Safari 10 bugs
compress: {
inline: false, // Buggy
},
},
}),
],

runtimeChunk: true,

// See https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
Expand All @@ -67,6 +87,8 @@ const clientSpecificConfig = {
},
},

devtool: isDev ? 'cheap-module-source-map' : 'source-map',

stats: 'errors-only',

// Enforce performance limits for production build if PERF flag is set
Expand Down Expand Up @@ -117,10 +139,6 @@ const clientSpecificConfig = {
include: 'initial',
}),

new webpack.DefinePlugin(
mapValues(getAppGlobals(), v => JSON.stringify(v)),
),

...ifProd([
// @ts-ignore
new StatsWriterPlugin({
Expand Down
67 changes: 67 additions & 0 deletions src/webpack/webpack.config.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const slsw = require('serverless-webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const path = require('path');
const { compact } = require('lodash');

const { createScriptRules } = require('./helpers');
const { createBaseConfig } = require('./createBaseConfig');

const common = createBaseConfig();

const serverSpecificConfig = {
entry: slsw.lib.entries,
target: 'node',
node: {
__dirname: true,
},

devtool: false,

externals: ['express', 'http-proxy-middleware', 'helmet', 'aws-sdk'],

optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
keep_classnames: true,
compress: {
inline: false,
},
},
}),
],
},

output: {
libraryTarget: 'commonjs',
path: path.resolve(__dirname, '.webpack'),
filename: '[name].js',
},

stats: 'minimal',

module: {
rules: compact([
// JavaScript and TypeScript
...createScriptRules({ isNode: true }),
]),
},

resolve: {
modules: [path.join(__dirname, '..')],
},

plugins: compact([
new webpack.IgnorePlugin(/^electron$/),
new webpack.IgnorePlugin(/^yamlparser$/),

// @ts-ignore
new CopyWebpackPlugin([{ from: 'dist', to: 'dist' }]),
]),
};

module.exports = webpackMerge(common, serverSpecificConfig);
Loading