Skip to content

Commit 979cfc6

Browse files
committed
Initial commit
0 parents  commit 979cfc6

15 files changed

+6834
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.DS_STORE
3+
*.log

.prettierrc.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
trailingComma: 'es5',
3+
singleQuote: true,
4+
};

.vscode/launch.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Debug Jest Tests",
6+
"type": "node",
7+
"request": "launch",
8+
"runtimeArgs": [
9+
"--inspect-brk",
10+
"${workspaceRoot}/node_modules/.bin/jest",
11+
"--runInBand"
12+
],
13+
"console": "integratedTerminal",
14+
"internalConsoleOptions": "neverOpen",
15+
"port": 9229
16+
},
17+
{
18+
"name": "Debug Current Jest File",
19+
"type": "node",
20+
"request": "launch",
21+
"runtimeArgs": [
22+
"--inspect-brk",
23+
"${workspaceRoot}/node_modules/.bin/jest",
24+
"--runInBand",
25+
"${file}"
26+
],
27+
"console": "integratedTerminal",
28+
"internalConsoleOptions": "neverOpen",
29+
"port": 9229
30+
}
31+
]
32+
}

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Terraform Next.js Image Optimization module for AWS
2+
3+
A drop-in image optimization [loader](https://nextjs.org/docs/basic-features/image-optimization#loader) for Next.js image component `next/image`.
4+
5+
## Features
6+
7+
This module is currently under active development.
8+
9+
- 🚧 CloudFront powered image caching
10+
- 🚧 S3 powered image cache with automatic expiration
11+
- 🚧 CORS based security rules (Only allow image embed from defined domains)
12+
- 🚧 Support for [Device Sizes](https://nextjs.org/docs/basic-features/image-optimization#device-sizes)
13+
- 🚧 Support for [Image Sizes](https://nextjs.org/docs/basic-features/image-optimization#image-sizes)
14+
15+
## Usage
16+
17+
## Versioning
18+
19+
We internally rely on the Next.js image optimizer, so every version we publish follows the versioning schema of the [Next.js package](https://www.npmjs.com/package/next).
20+
21+
## License
22+
23+
Apache-2.0 - see [LICENSE](./LICENSE) for details.

buildimage.Dockerfile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Buildimage used for creating a local build
2+
# Since it is intended to run on Amazon Linux we need to install binaries
3+
# for the internally used sharp package that match this distribution
4+
5+
FROM registry.gitlab.com/dealmore/dealmore-build-images/lambdaci:nodejs12.x
6+
7+
RUN yarn --frozen-lockfile

jest.config.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
rootDir: './',
5+
// globals: {
6+
// 'ts-jest': {
7+
// tsconfig: 'tsconfig.test.json',
8+
// },
9+
// },
10+
};

lib/declarations.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module NodeJS {
2+
interface Global {
3+
fetch: any;
4+
}
5+
}

lib/image-optimizer.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { IncomingMessage, ServerResponse } from 'http';
2+
import { imageOptimizer as nextImageOptimizer } from 'next/dist/next-server/server/image-optimizer';
3+
import { ImageConfig } from 'next/dist/next-server/server/image-config';
4+
import nodeFetch from 'node-fetch';
5+
6+
import { UrlWithParsedQuery } from 'url';
7+
import Server from 'next/dist/next-server/server/next-server';
8+
9+
// Polyfill fetch used by nextImageOptimizer
10+
global.fetch = nodeFetch;
11+
12+
function imageOptimizer(
13+
imageConfig: ImageConfig,
14+
req: IncomingMessage,
15+
res: ServerResponse,
16+
parsedUrl: UrlWithParsedQuery
17+
) {
18+
// Create Next Server mock
19+
const server = ({
20+
nextConfig: {
21+
images: imageConfig,
22+
},
23+
distDir: '/tmp',
24+
getRequestHandler: () => () => {
25+
console.log('Here!');
26+
},
27+
} as unknown) as Server;
28+
29+
return nextImageOptimizer(server, req, res, parsedUrl);
30+
}
31+
32+
export { imageOptimizer };

lib/package.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "@dealmore/tf-next-image-optimization",
3+
"version": "10.0.5-pre.001",
4+
"license": "Apache-2.0",
5+
"dependencies": {
6+
"next": "10.0.5",
7+
"node-fetch": "^2.6.1"
8+
},
9+
"devDependencies": {
10+
"@types/node-fetch": "^2.5.7"
11+
}
12+
}

package.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "workspace-root",
3+
"version": "0.0.0",
4+
"private": true,
5+
"license": "Apache-2.0",
6+
"workspaces": [
7+
"lib"
8+
],
9+
"scripts": {
10+
"test": "jest"
11+
},
12+
"devDependencies": {
13+
"@types/jest": "^26.0.20",
14+
"@types/node": "^12.0.0",
15+
"jest": "^26.6.3",
16+
"node-mocks-http": "^1.10.0",
17+
"prettier": "^2.2.1",
18+
"ts-jest": "^26.4.4",
19+
"typescript": "^4.1.3"
20+
}
21+
}

test/image-optimizer.test.ts

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { createRequest, createResponse } from 'node-mocks-http';
2+
import { parse as parseUrl, URLSearchParams } from 'url';
3+
import { EventEmitter } from 'events';
4+
import {
5+
ImageConfig,
6+
imageConfigDefault,
7+
} from 'next/dist/next-server/server/image-config';
8+
9+
import { imageOptimizer } from '../lib/image-optimizer';
10+
import { createDeferred } from './utils';
11+
12+
interface Options {
13+
w?: string;
14+
q?: string;
15+
}
16+
17+
function generateParams(url: string, options: Options = {}) {
18+
const encodedUrl = encodeURIComponent(url);
19+
const params = new URLSearchParams();
20+
params.append('url', url);
21+
options.q && params.append('q', options.q);
22+
options.w && params.append('w', options.w);
23+
24+
const parsedUrl = parseUrl(`/?${params.toString()}`, true);
25+
26+
return {
27+
url: encodedUrl,
28+
parsedUrl,
29+
params: Object.fromEntries(params),
30+
};
31+
}
32+
33+
describe('[unit] imageOptimizer', () => {
34+
test('', async () => {
35+
const imageConfig: ImageConfig = {
36+
...imageConfigDefault,
37+
domains: ['upload.wikimedia.org'],
38+
};
39+
40+
const params = generateParams(
41+
'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Macaca_nigra_self-portrait_large.jpg/1024px-Macaca_nigra_self-portrait_large.jpg',
42+
{
43+
w: '2048',
44+
q: '75',
45+
}
46+
);
47+
48+
// Mock request & response
49+
const request = createRequest({
50+
method: 'GET',
51+
url: '/image',
52+
params: params.params,
53+
});
54+
const response = createResponse({
55+
eventEmitter: EventEmitter,
56+
});
57+
58+
const defer = createDeferred();
59+
60+
response.on('send', (chunk: any) => {
61+
console.log(response._getData());
62+
});
63+
64+
response.on('end', () => {
65+
defer.resolve();
66+
});
67+
68+
const result = await imageOptimizer(
69+
imageConfig,
70+
request,
71+
response,
72+
params.parsedUrl
73+
);
74+
75+
const header = response._getHeaders();
76+
const body = response._getBuffer();
77+
78+
expect(result.finished).toBe(true);
79+
80+
await defer.promise;
81+
});
82+
});

test/tsconfig.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"include": ["./**/*"]
4+
}

test/utils.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export interface Deferred<T = never> {
2+
promise: Promise<T>;
3+
resolve: (value?: T | PromiseLike<T>) => void;
4+
reject: (reason?: any) => void;
5+
}
6+
7+
export function createDeferred<T>() {
8+
let r;
9+
let j;
10+
11+
const promise = new Promise<T>(
12+
(resolve: (value: any) => void, reject: (reason?: any) => void): void => {
13+
r = resolve;
14+
j = reject;
15+
}
16+
);
17+
18+
return ({ promise, resolve: r, reject: j } as unknown) as Deferred<T>;
19+
}

tsconfig.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2019",
4+
"lib": ["es2019"],
5+
"outDir": "dist",
6+
"module": "commonjs",
7+
"moduleResolution": "node",
8+
"strict": true,
9+
"declaration": false,
10+
"sourceMap": false,
11+
"experimentalDecorators": true,
12+
"esModuleInterop": true
13+
},
14+
"include": ["lib/**/*"]
15+
}

0 commit comments

Comments
 (0)