Skip to content

Commit

Permalink
Serve compressed assets in dist mode (dojo#214)
Browse files Browse the repository at this point in the history
When serving in dist mode without memory watch, use express-static-gzip
instead of express.static in order to serve compressed build files.
  • Loading branch information
mwistrand committed Nov 29, 2018
1 parent ba15007 commit 537d7f4
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ An array of paths to [CLDR JSON](https://github.com/dojo/i18n#loading-cldr-data)

#### `compression`: Array<'gzip' | 'brotli'>

Options for compression when running in `dist` mode. Each array value represents a different algorithm, allowing both gzip and brotli builds to be output side-by-side.
Options for compression when running in `dist` mode. Each array value represents a different algorithm, allowing both gzip and brotli builds to be output side-by-side. When used in conjunction with the `--serve` flag (in `dist` mode _without_ memory watch), the compressed files will be served, with brotli preferred over gzip when available.

### `externals`: object

Expand Down
42 changes: 25 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"css-loader": "0.28.7",
"eventsource-polyfill": "0.9.6",
"express": "4.16.2",
"express-static-gzip": "1.1.3",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"globby": "7.1.1",
Expand Down
13 changes: 12 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as proxy from 'http-proxy-middleware';
import * as history from 'connect-history-api-fallback';

const pkgDir = require('pkg-dir');
const expressStaticGzip = require('express-static-gzip');
import devConfigFactory from './dev.config';
import unitConfigFactory from './unit.config';
import functionalConfigFactory from './functional.config';
Expand Down Expand Up @@ -170,7 +171,17 @@ function serve(config: webpack.Configuration, args: any): Promise<void> {

if (args.watch !== 'memory') {
const outputDir = (config.output && config.output.path) || process.cwd();
app.use(express.static(outputDir));
if (args.mode === 'dist' && Array.isArray(args.compression)) {
const useBrotli = args.compression.includes('brotli');
app.use(
expressStaticGzip(outputDir, {
enableBrotli: useBrotli,
orderPreference: useBrotli ? ['br'] : undefined
})
);
} else {
app.use(express.static(outputDir));
}
}

if (args.proxy) {
Expand Down
68 changes: 68 additions & 0 deletions tests/unit/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('command', () => {
'./unit.config',
'connect-history-api-fallback',
'express',
'express-static-gzip',
'http-proxy-middleware',
'https',
'log-update',
Expand Down Expand Up @@ -540,6 +541,73 @@ describe('command', () => {
});
});

it('serves compressed files in dist mode', () => {
const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor;
const main = mockModule.getModuleUnderTest().default;
const outputDir = '/output/dist';
const rc = {
mode: 'dist',
compression: ['gzip'],
serve: true
};
output.path = outputDir;
return main.run(getMockConfiguration(), rc).then(() => {
assert.isTrue(
expressStaticGzip.calledWith(outputDir, {
enableBrotli: false,
orderPreference: undefined
})
);
});
});

it('does not serve compressed files in dev mode', () => {
const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor;
const main = mockModule.getModuleUnderTest().default;
const rc = {
mode: 'dev',
compression: ['gzip'],
serve: true
};
return main.run(getMockConfiguration(), rc).then(() => {
assert.isFalse(expressStaticGzip.called);
});
});

it('does not serve compressed files with memory watch', () => {
const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor;
const main = mockModule.getModuleUnderTest().default;
const rc = {
mode: 'dist',
compression: ['gzip'],
serve: true,
watch: 'memory'
};
return main.run(getMockConfiguration(), rc).then(() => {
assert.isFalse(expressStaticGzip.called);
});
});

it('favors brotli over gzip', () => {
const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor;
const main = mockModule.getModuleUnderTest().default;
const outputDir = '/output/dist';
const rc = {
mode: 'dist',
compression: ['gzip', 'brotli'],
serve: true
};
output.path = outputDir;
return main.run(getMockConfiguration(), rc).then(() => {
assert.isTrue(
expressStaticGzip.calledWith(outputDir, {
enableBrotli: true,
orderPreference: ['br']
})
);
});
});

describe('https', () => {
it('starts an https server if key and cert are available', () => {
const main = mockModule.getModuleUnderTest().default;
Expand Down

0 comments on commit 537d7f4

Please sign in to comment.