\n \n\n"
782 | }
783 | ```
784 |
785 |
786 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### 0.5.8 (2022-02-09)
6 |
7 |
8 | ### Features
9 |
10 | * add decode option to test-lambda to return plain html ([c94eee0](https://github.com/pimlie/nuxt-lambda/commit/c94eee0d434aa5d72d91a74819b4477cc79d388f))
11 | * add excludeClientFiles option to exclude assets from the nuxt lambda ([9c5494e](https://github.com/pimlie/nuxt-lambda/commit/9c5494e3232b924a97f8bad1a752dce777b3134c))
12 | * add support for (optionally) serving static files ([15076c1](https://github.com/pimlie/nuxt-lambda/commit/15076c1a84958b2d1e92e330e94275153169620d))
13 | * add support for excludeFiles config ([6ada5de](https://github.com/pimlie/nuxt-lambda/commit/6ada5de4cd50ac61856761109bd51d3d0d5c275a))
14 | * add support for pssing options to zisi ([0847895](https://github.com/pimlie/nuxt-lambda/commit/0847895a66894cfb6599e6fc26b4e1b873ad922d))
15 | * add support for rendering error page on internal server error ([8a33241](https://github.com/pimlie/nuxt-lambda/commit/8a33241af126a13fb5dcedf0ccc5fb060479209b))
16 | * add support to build full lambda (optimize is default) ([2f59fd5](https://github.com/pimlie/nuxt-lambda/commit/2f59fd540de31f51122c5178f10a97cf3f2655f6))
17 | * improve modern build support ([c36ac08](https://github.com/pimlie/nuxt-lambda/commit/c36ac082b16bfff2d4e82c9ca2f3ca64c884c4e1))
18 | * refactoring, better support for different handlers ([ba3bcc2](https://github.com/pimlie/nuxt-lambda/commit/ba3bcc25733ac3803cb897cefb12f95ce6bdaac7))
19 | * support separate build/dir dirs ([7caffda](https://github.com/pimlie/nuxt-lambda/commit/7caffdae9992f1dc631667095cf5b1bd94e4530d))
20 |
21 |
22 | ### Bug Fixes
23 |
24 | * add better stub for consola ([73629b3](https://github.com/pimlie/nuxt-lambda/commit/73629b34497a13215402026d4d1d32f696684b0a))
25 | * add bracket syntax for replacing consola ([36c270a](https://github.com/pimlie/nuxt-lambda/commit/36c270ab499124102727a8fadc46d32591aa628b))
26 | * allow setting handler in nuxt.options again ([50c40c5](https://github.com/pimlie/nuxt-lambda/commit/50c40c5d2aee8372f02a1299485dea7eec982f30))
27 | * an unknown config issue ([dd790c4](https://github.com/pimlie/nuxt-lambda/commit/dd790c456fdf250a0b5cdb99d21050a811f1798b))
28 | * by default always add files to zip (duh) ([30c08ac](https://github.com/pimlie/nuxt-lambda/commit/30c08aca7426feebd013b700a9c6dca85d5c6d3a))
29 | * chore update dependencies ([3237a69](https://github.com/pimlie/nuxt-lambda/commit/3237a690624e5a6b6935a6397ead336ece49c223))
30 | * exclude is not add to zip ([f2f2993](https://github.com/pimlie/nuxt-lambda/commit/f2f2993827b701989039e83d35f2249662503c24))
31 | * nuxt config changes ([281d259](https://github.com/pimlie/nuxt-lambda/commit/281d259124304c9b79fc7933a81fa452e3c15ab2))
32 | * remove unnecessary replace ([9055d99](https://github.com/pimlie/nuxt-lambda/commit/9055d99b52d2130f399ab6b1ce073579f9790415))
33 | * **renderer:** provide `nuxt.options` ([3e90db7](https://github.com/pimlie/nuxt-lambda/commit/3e90db7d13e2402b8da2ae52061a8dae53115da7))
34 | * **renderer:** provide `nuxt.options` ([1fccb1c](https://github.com/pimlie/nuxt-lambda/commit/1fccb1c1e91ecf3a358da464bc26b9aa4bf99ec0))
35 | * replace routePath in nuxt context ([2b8bdd2](https://github.com/pimlie/nuxt-lambda/commit/2b8bdd27d23c667020214855fdb9dd9c10650eee))
36 | * revert build script changes ([477d93f](https://github.com/pimlie/nuxt-lambda/commit/477d93f058c30543a90a4ff21ab31da503cec121))
37 | * root/build dir issue ([a0dc0d6](https://github.com/pimlie/nuxt-lambda/commit/a0dc0d6a3adb70db92f6a34d71e68e992437cbf4))
38 | * serialize/eval shouldPrefetch/Preload functions ([2273537](https://github.com/pimlie/nuxt-lambda/commit/2273537b9cb006cec1a01797400946084694f688))
39 | * support nuxt v2.12 ([515b2a0](https://github.com/pimlie/nuxt-lambda/commit/515b2a0746870d439437f1738ce951b497dc6f50))
40 | * upgrade to @babel/eslint-parser ([966133b](https://github.com/pimlie/nuxt-lambda/commit/966133b537fefc194121d9ca870a9b78040dd5fd))
41 |
42 | ### [0.5.7](https://github.com/pimlie/nuxt-lambda/compare/v0.5.6...v0.5.7) (2021-09-28)
43 |
44 |
45 | ### Features
46 |
47 | * improve modern build support ([c36ac08](https://github.com/pimlie/nuxt-lambda/commit/c36ac082b16bfff2d4e82c9ca2f3ca64c884c4e1))
48 |
49 | ### [0.5.6](https://github.com/pimlie/nuxt-lambda/compare/v0.5.5...v0.5.6) (2021-06-12)
50 |
51 |
52 | ### Features
53 |
54 | * add decode option to test-lambda to return plain html ([c94eee0](https://github.com/pimlie/nuxt-lambda/commit/c94eee0d434aa5d72d91a74819b4477cc79d388f))
55 |
56 |
57 | ### Bug Fixes
58 |
59 | * replace routePath in nuxt context ([2b8bdd2](https://github.com/pimlie/nuxt-lambda/commit/2b8bdd27d23c667020214855fdb9dd9c10650eee))
60 |
61 | ### [0.5.5](https://github.com/pimlie/nuxt-lambda/compare/v0.5.4...v0.5.5) (2021-06-12)
62 |
63 |
64 | ### Features
65 |
66 | * add support for rendering error page on internal server error ([8a33241](https://github.com/pimlie/nuxt-lambda/commit/8a33241af126a13fb5dcedf0ccc5fb060479209b))
67 |
68 |
69 | ### Bug Fixes
70 |
71 | * upgrade to @babel/eslint-parser ([966133b](https://github.com/pimlie/nuxt-lambda/commit/966133b537fefc194121d9ca870a9b78040dd5fd))
72 |
73 | ### [0.5.4](https://github.com/pimlie/nuxt-lambda/compare/v0.5.3...v0.5.4) (2021-02-25)
74 |
75 |
76 | ### Bug Fixes
77 |
78 | * chore update dependencies ([3237a69](https://github.com/pimlie/nuxt-lambda/commit/3237a690624e5a6b6935a6397ead336ece49c223))
79 |
80 | ### [0.5.3](https://github.com/pimlie/nuxt-lambda/compare/v0.5.2...v0.5.3) (2020-09-23)
81 |
82 |
83 | ### Bug Fixes
84 |
85 | * exclude is not add to zip ([f2f2993](https://github.com/pimlie/nuxt-lambda/commit/f2f2993827b701989039e83d35f2249662503c24))
86 |
87 | ### [0.5.2](https://github.com/pimlie/nuxt-lambda/compare/v0.5.1...v0.5.2) (2020-09-22)
88 |
89 |
90 | ### Features
91 |
92 | * add support for excludeFiles config ([6ada5de](https://github.com/pimlie/nuxt-lambda/commit/6ada5de4cd50ac61856761109bd51d3d0d5c275a))
93 |
94 | ### [0.5.1](https://github.com/pimlie/nuxt-lambda/compare/v0.5.0...v0.5.1) (2020-09-16)
95 |
96 |
97 | ### Bug Fixes
98 |
99 | * by default always add files to zip (duh) ([30c08ac](https://github.com/pimlie/nuxt-lambda/commit/30c08aca7426feebd013b700a9c6dca85d5c6d3a))
100 |
101 | ## [0.5.0](https://github.com/pimlie/nuxt-lambda/compare/v0.4.4...v0.5.0) (2020-09-16)
102 |
103 |
104 | ### Features
105 |
106 | * add excludeClientFiles option to exclude assets from the nuxt lambda ([9c5494e](https://github.com/pimlie/nuxt-lambda/commit/9c5494e3232b924a97f8bad1a752dce777b3134c))
107 |
108 | ### [0.4.4](https://github.com/pimlie/nuxt-lambda/compare/v0.4.3...v0.4.4) (2020-09-03)
109 |
110 |
111 | ### Bug Fixes
112 |
113 | * add better stub for consola ([73629b3](https://github.com/pimlie/nuxt-lambda/commit/73629b34497a13215402026d4d1d32f696684b0a))
114 | * **renderer:** provide `nuxt.options` ([3e90db7](https://github.com/pimlie/nuxt-lambda/commit/3e90db7d13e2402b8da2ae52061a8dae53115da7))
115 | * **renderer:** provide `nuxt.options` ([1fccb1c](https://github.com/pimlie/nuxt-lambda/commit/1fccb1c1e91ecf3a358da464bc26b9aa4bf99ec0))
116 |
117 | ### [0.4.3](https://github.com/pimlie/nuxt-lambda/compare/v0.4.2...v0.4.3) (2020-05-04)
118 |
119 |
120 | ### Bug Fixes
121 |
122 | * add bracket syntax for replacing consola ([36c270a](https://github.com/pimlie/nuxt-lambda/commit/36c270ab499124102727a8fadc46d32591aa628b))
123 |
124 | ### [0.4.2](https://github.com/pimlie/nuxt-lambda/compare/v0.4.1...v0.4.2) (2020-04-06)
125 |
126 |
127 | ### Bug Fixes
128 |
129 | * support nuxt v2.12 ([515b2a0](https://github.com/pimlie/nuxt-lambda/commit/515b2a0746870d439437f1738ce951b497dc6f50))
130 |
131 | ### [0.4.1](https://github.com/pimlie/nuxt-lambda/compare/v0.4.0...v0.4.1) (2020-03-24)
132 |
133 |
134 | ### Bug Fixes
135 |
136 | * remove unnecessary replace ([9055d99](https://github.com/pimlie/nuxt-lambda/commit/9055d99b52d2130f399ab6b1ce073579f9790415))
137 |
138 | ## [0.4.0](https://github.com/pimlie/nuxt-lambda/compare/v0.3.0...v0.4.0) (2020-02-27)
139 |
140 |
141 | ### Features
142 |
143 | * add support for (optionally) serving static files ([15076c1](https://github.com/pimlie/nuxt-lambda/commit/15076c1a84958b2d1e92e330e94275153169620d))
144 |
145 |
146 | ### Bug Fixes
147 |
148 | * allow setting handler in nuxt.options again ([50c40c5](https://github.com/pimlie/nuxt-lambda/commit/50c40c5d2aee8372f02a1299485dea7eec982f30))
149 |
150 | ## [0.3.0](https://github.com/pimlie/nuxt-lambda/compare/v0.2.2...v0.3.0) (2020-02-16)
151 |
152 |
153 | ### Features
154 |
155 | * refactoring, better support for different handlers ([ba3bcc2](https://github.com/pimlie/nuxt-lambda/commit/ba3bcc25733ac3803cb897cefb12f95ce6bdaac7))
156 |
157 |
158 | ### Bug Fixes
159 |
160 | * revert build script changes ([477d93f](https://github.com/pimlie/nuxt-lambda/commit/477d93f058c30543a90a4ff21ab31da503cec121))
161 | * serialize/eval shouldPrefetch/Preload functions ([2273537](https://github.com/pimlie/nuxt-lambda/commit/2273537b9cb006cec1a01797400946084694f688))
162 |
163 | ### [0.2.2](https://github.com/pimlie/nuxt-lambda/compare/v0.2.1...v0.2.2) (2020-02-03)
164 |
165 |
166 | ### Bug Fixes
167 |
168 | * an unknown config issue ([dd790c4](https://github.com/pimlie/nuxt-lambda/commit/dd790c456fdf250a0b5cdb99d21050a811f1798b))
169 |
170 | ### [0.2.1](https://github.com/pimlie/nuxt-lambda/compare/v0.2.0...v0.2.1) (2020-02-03)
171 |
172 |
173 | ### Features
174 |
175 | * support separate build/dir dirs ([7caffda](https://github.com/pimlie/nuxt-lambda/commit/7caffdae9992f1dc631667095cf5b1bd94e4530d))
176 |
177 | ## [0.2.0](https://github.com/pimlie/nuxt-lambda/compare/v0.1.0...v0.2.0) (2020-02-02)
178 |
179 |
180 | ### Features
181 |
182 | * add support to build full lambda (optimize is default) ([2f59fd5](https://github.com/pimlie/nuxt-lambda/commit/2f59fd540de31f51122c5178f10a97cf3f2655f6))
183 |
184 | ## 0.1.0 (2020-02-02)
185 |
186 |
187 | ### Bug Fixes
188 |
189 | * root/build dir issue ([a0dc0d6](https://github.com/pimlie/nuxt-lambda/commit/a0dc0d6a3adb70db92f6a34d71e68e992437cbf4))
190 |
191 | ## 0.1.0 (2020-02-02)
192 |
193 |
194 | ### Bug Fixes
195 |
196 | * root/build dir issue ([a0dc0d6](https://github.com/pimlie/nuxt-lambda/commit/a0dc0d6a3adb70db92f6a34d71e68e992437cbf4))
197 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) pimlie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nuxt command to create a Nuxt.js lambda (beta)
2 | [![npm version][npm-version-src]][npm-version-href]
3 | [![npm downloads][npm-downloads-src]][npm-downloads-href]
4 | [![License][license-src]][license-href]
5 |
6 | ### :warning: Optimized build by default with limited Nuxt.js functionality
7 |
8 | > You can enable the full Nuxt.js handler by setting `lambda.handler: 'full'` in your nuxt.config
9 |
10 | This command will by default create a lambda for Nuxt.js SSR that is optimized to run serverless. That means most non-essential Nuxt.js SSR features have been stripped out.
11 |
12 | - No connect server (it uses @nuxt/vue-renderer directly instead of going through @nuxt/server)
13 | - No support for runtime modules (only buildModules)
14 | - No support for server middlewares (although we might be able to add support for this at a later time)
15 | - No support for serving static files (there is optional support for the connect handler)
16 | - No support for hooks
17 |
18 | ### Possible tunables
19 |
20 | - turn off compression `render.compressor: false`
21 | - turn off etags `render.etag: false`
22 |
23 | ## How to use
24 |
25 | #### Install
26 | ```js
27 | $ yarn add nuxt-lambda
28 | ```
29 |
30 | #### Configure (optional)
31 |
32 | See [Options](#options) below
33 |
34 | #### Build & test
35 |
36 | See [Commands](#commands)
37 |
38 | ## Commands
39 |
40 | ### nuxt-lambda
41 |
42 | The command to build a lambda. See `-h` for all available options (not all are supported).
43 |
44 | It will by default create a `.lambda` dir in your rootDir containing the intermediates and a `dist` folder with the zip file you need to upload
45 |
46 | ```js
47 | $ yarn nuxt-lambda [-c nuxt.config.js]
48 |
49 | // eg: yarn nuxt-lambda src
50 | ```
51 |
52 | - `--handler`
53 |
54 | Same as `options.lambda.handler`, see [Options](#options). Used to quickly override the handler you want to use
55 |
56 | - `--static`
57 |
58 | Same as `options.lambda.static`, see [Options](#options). Used to quickly override whether to enable support for serving static files or not
59 |
60 | - `--no-optimize`
61 |
62 | _Not supported yet_
63 |
64 | - `--no-nuxt`
65 |
66 | Build a lambda without re-building your Nuxt.js project.
67 |
68 | - `--no-lambda`
69 |
70 | _Not supported yet_
71 |
72 | - `--no-zip`
73 |
74 | _Not supported yet_
75 |
76 | ### test-lambda
77 |
78 | The command to test a lambda. See `-h` for available options.
79 |
80 | Accepts either a path to a nuxt rootDir or a path to a packed lambda zip file.
81 |
82 | ```js
83 | $ yarn test-lambda
84 |
85 | // eg: yarn test-lambda src /about
86 | // eg: yarn test-lambda /about
87 | ```
88 |
89 | - `-p`, `--persistent`
90 |
91 | Normally when running test-lambda the lambda is unzipped in a temporary directory which is cleaned-up when the lambda has finished. Passing the persistent option unpacks the lambda in the `options.lambda.distDir` folder instead only when it doesnt exists yet
92 |
93 | - `--debug`
94 |
95 | If your lambda was built with `debug: true` in your nuxt.config, use this switch to toggle verbose logging
96 |
97 | ## Available Handlers
98 |
99 | #### connect (default)
100 |
101 | This is an optimized handler that uses `connect` & `serverless-http` to process requests without starting a full blown server.
102 |
103 | #### minimal (experimental, proof of concept)
104 |
105 | This is an extremely optimized handler, it uses abstracted implementations for most dependencies which cannot be tree-shaked but have a reasonable effect on cold-boot / execution times.
106 |
107 | > Dont use this handler yet in production until we have implemented more tests
108 |
109 | - no `serverless-http`, uses a lightweight custom implementation
110 | - `fs-extra` is stubbed with a lightweight custom implementation
111 | - a custom `compression` middleware is used
112 |
113 | Preliminary savings seem to be around ~10ms compared to the connect handler
114 |
115 | #### full
116 |
117 | Just start a full-blown Nuxt.js server instance with all Nuxt.js features and dependencies. Not optimized at all, provided as fallback so you can still benefit from the packaging this command provides
118 |
119 | ## Debugging
120 |
121 | For the optimized handlers, make sure to set `debug: true` in your `nuxt.config`. Then re-build your lambda & run the `test-lambda` command with `--debug`
122 |
123 | Debugging is implemented by returning a Proxy for the `res` and `req` variables which logs any `get`, `set` or `call` command. When you have compression enabled, it also prints debug logs about compression.
124 |
125 | Also when `debug: true` the lambda wont be minimized, so you can check the file `${options.lambda.buildDir}/${options.lambda.name}.js` to debug the webpack build
126 |
127 | ## Options
128 |
129 | You can add a `lambda` section in your nuxt.config with the following properties
130 |
131 | - `name` (default: _nuxt_)
132 |
133 | The name of your lambda, ie the zip will be named `.zip`. Dont change this for now if you want to run the test-lambda command
134 |
135 | - `handler` (default: _connect_)
136 |
137 | Either `full`, `connect` or `minimal`. See [available handlers](#available-handlers)
138 |
139 | - `buildDir` (default: _.lambda_)
140 |
141 | The name of the folder where the intermediates for the lambda build are saved (dont use nuxt's buildDir, config is created before nuxt build which removes the nuxt builddir). If relative then relative to _rootDir_
142 |
143 | - `distDir` (default: _dist_)
144 |
145 | The name of the folder where the zipped lambda will be saved. If relative then relative to _rootDir_
146 |
147 | - `spa` (default: _false_)
148 |
149 | This is intended to be an override when you are using universal mode but have some single pages running as SPA. In essence it will _not_ optimize the lambda by removing SPA-only features
150 |
151 | - `static` (default: _false_)
152 |
153 | If true then full support for serving static files from `nuxt.options.dir.static` will also be added to the lambda.
154 |
155 | For the full handler this means the serve-static middleware can resolve all static files
156 | For the connect handler the serve-static middleware is added to handle static file loading (but only when `static: true`)
157 | For the minimal handler this option only adds the files, so you probably shouldnt use this (there is no safeguard though)
158 |
159 | - `zisi` (default: _undefined_)
160 |
161 | Options passed to zisi. See [@netlify/zip-it-and-ship-it](https://github.com/netlify/zip-it-and-ship-it)
162 |
163 | - `excludeClientFiles` (default: _undefined_)
164 |
165 | Used to exclude certain assets from Nuxt's dist/client directory to be included in the Nuxt lambda zip file. Useful when you are combining your lambda with a static file deployment and are using image, video etc assets in your application. Those assets dont need to be included in the lambda zip file when you also deploy all your client files statically already.
166 |
167 | Can either be an array of paths or a function. If an array then each file from the `.nuxt/dist/client` folder is only added when they don't start with the given path. We only support startsWith for now because this feature should be used in conjunction with Nuxt's `build.filenames` property to move certain file types to a specific subfolder
168 |
169 | If a function is provided it receives the relative path to the client folder as first argument, and the full (absolute) filename as second argument
170 |
171 | Example
172 | ```js
173 | // nuxt.config.js
174 | build: {
175 | filenames: {
176 | img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[contenthash:7].[ext]',
177 | }
178 | },
179 | lambda: {
180 | excludeClientFiles: ['img/'],
181 | // or
182 | excludeClientFiles: clientAssetPath => !clientAssetPath.startsWith('img/'),
183 | }
184 | ```
185 |
186 | - `excludeFiles` (default: _undefined_)
187 |
188 | Similar to `excludeClientFiles` but can be used to also filter server files. Recieves the file path related from `.nuxt`.
189 |
190 | Example
191 | ```js
192 | // nuxt.config.js
193 | build: {
194 | filenames: {
195 | img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[contenthash:7].[ext]',
196 | }
197 | },
198 | lambda: {
199 | excludeFiles: ['dist/client/img/'], // same as excludeClientFiles example above
200 | // or
201 | excludeFiles: filePath => filePath.endsWith('.map'), // ignore all sourcemaps
202 | }
203 | ```
204 |
205 | - `webpack` (default: _null_)
206 |
207 | Any additional webpack config that is needed for your lambda build. At the moment it doesnt make really sense to touch this
208 |
209 | ## Benchmarks
210 |
211 | Please check [Benchmarks](./BENCHMARKS.md)
212 |
213 | #### Remarks about `/` page
214 |
215 | This page uses the uuid plugin, which means its expected that checksums for the response are _never_ the same
216 |
217 | #### Remarks about `/about` page
218 |
219 | This page does a request to a 3rd pary API, differences in execution time are likely caused by variance in contacting this API
220 |
221 | #### Remarks about `/redirect` page
222 |
223 | `serverless-http` up to `v2.3.1` contains a [bug](https://github.com/dougmoscrop/serverless-http/pull/137) which causes Nuxt.js redirections to fail unless a previous header has been set
224 |
225 | #### Remarks about `/nuxt-icon.png` file
226 |
227 | This file should only return a 200 for the full and connect handlers and the `with-static` config. The checksums wont be the same due to differences in last-modified times
228 |
229 | ### Running the benchmarks
230 |
231 | The benchmark command is located in `./benchmark/run.js`
232 |
233 | #### arguments
234 |
235 | - `--results ` (optional)
236 |
237 | Point to a previous created results file instead of running a new benchmark. Useful for markdown tweaking.
238 |
239 | - `--runs `
240 |
241 | If you want to change the default number of runs (which is 3)
242 |
243 | ## Rationale for using the optimized handler by default
244 |
245 | A lambda should be very good at running a single task, ie have a single responsibility. Nuxt will by default start a connect server which provides a similar abstraction layer as lambdas provide. The connect server is actually a very strong feature of Nuxt.js, it helps greatly to simplify deployments. But there are also cases where you dont need this abstraction (anymore) or where this second abstraction layer is just the _wrong_ approach because you deploy serverless. Eg a common approach is to use Nuxt.js serverMiddleware's to deploy an API, but when you are deploying serverless that API should really be run in a separate lambda.
246 |
247 | ##### Why is a single responsibility important?
248 |
249 | Most important/practical reason is cold boot performance of the lambda. A lambda is started for every single request, although the lambda context might be 'warm' from a previous request there are no guarantees that it will still be warm. Response times/performance of your Nuxt.js website could vary greatly because of this.
250 |
251 | Having a single responsibility means less dependencies, less code to parse so quicker cold boots:
252 |
253 | |Lambda implementation|Memory|Cold boot time|
254 | |---|---|---|
255 | |Full Nuxt.js|1GB|~500ms|
256 | |Full Nuxt.js|1.5GB|~300ms|
257 | |nuxt-lambda|1GB|~175ms|
258 | |nuxt-lambda|1.5GB|?|
259 |
260 | More information about AWS cold starts in this excellent article by @MikhailShilkov: [Cold Starts in AWS Lambda](https://mikhail.io/serverless/coldstarts/aws/)
261 |
262 | ## How does it work
263 |
264 | In general the lambda build consists of 4 steps:
265 |
266 | - Create a pre-normalized and optimized nuxt.config
267 | - Build Nuxt.js
268 | - Build Lambda, if using the optimized handler then stub any Nuxt.js feature/dependencies we dont need/want
269 | - Create a Zip file for the lambda:
270 | - Start with [@netlify/zip-it-and-ship-it](https://github.com/netlify/zip-it-and-ship-it) to zip the Nuxt.js lambda and all/just its dependencies
271 | - Then add all Nuxt.js resources from `//dist` to it
272 |
273 | ##### Is stubbing imports to optimize the lambda build really a good approach?
274 |
275 | Probably not, it would be better to fix these imports in Nuxt.js core. That might still happen, but stubbing gets us fastests to where we want to be for now. Also it will work with any Nuxt.js version and not just some future release.
276 |
277 | Eg just parsing/loading the `consola` dependency takes up to 10ms. Do we really need fancy logging in a lambda? Plain console should be good enough too, so we replace all `consola.` statements to `console.`.
278 |
279 | > This of course could break your code if you use non-standard log functions. Eg we have to set `render.ssrLog: false` because otherwise Nuxt.js will try to add a consola reporter
280 |
281 | ## Notice about running nuxt-lambda as Netlify function
282 |
283 | At the moment you cant both deploy static files and use a Netlify function as fallback for serving SSR routes due to a redirect issue on their platform. The issue causes your Nuxt function (often, but not always) to be preferred instead of the static files. Meaning that if you dont serve your static file _also_ with your lambda you will get 404's
284 |
285 | ## TODO
286 |
287 | - [ ] (minimal handler) Improve feature testing
288 | - [ ] (minimal/connect handler) Allow additional middleware's
289 | - [ ] (maybe) Try to pack `vue-server-renderer` in a single file (less files could be faster unzipping?)
290 | - [ ] (maybe) Provide Nuxt.js lambdas as AWS layers (we'd need to remove the stubbing and just use optional requires instead)
291 | - Then users really only have to deploy their `.nuxt/dist` folder
292 |
293 | ## License
294 |
295 | [MIT License](./LICENSE)
296 |
297 | Copyright (c) pimlie
298 |
299 |
300 | [npm-version-src]: https://img.shields.io/npm/v/nuxt-lambda/latest.svg?style=flat-square
301 | [npm-version-href]: https://npmjs.com/package/nuxt-lambda
302 |
303 | [npm-downloads-src]: https://img.shields.io/npm/dt/nuxt-lambda.svg?style=flat-square
304 | [npm-downloads-href]: https://npmjs.com/package/nuxt-lambda
305 |
306 | [circle-ci-src]: https://img.shields.io/circleci/project/github/pimlie/nuxt-lambda.svg?style=flat-square
307 | [circle-ci-href]: https://circleci.com/gh/pimlie/nuxt-lambda
308 |
309 | [codecov-src]: https://img.shields.io/codecov/c/github/pimlie/nuxt-lambda.svg?style=flat-square
310 | [codecov-href]: https://codecov.io/gh/pimlie/nuxt-lambda
311 |
312 | [license-src]: https://img.shields.io/npm/l/nuxt-lambda.svg?style=flat-square
313 | [license-href]: https://npmjs.com/package/nuxt-lambda
314 |
--------------------------------------------------------------------------------
/benchmark/configs/base.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | const rootDir = path.resolve(__dirname, '../../example')
4 |
5 | const baseConfig = require(`${rootDir}/nuxt.config.js`)
6 |
7 | export default {
8 | ...baseConfig.default,
9 | rootDir,
10 | render: {
11 | compressor: false,
12 | etag: false
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/benchmark/configs/with-compression.js:
--------------------------------------------------------------------------------
1 | import baseConfig from './base'
2 |
3 | export default {
4 | ...baseConfig,
5 | lambda: {
6 | buildDir: '.lambda-with-compression',
7 | distDir: 'dist-with-compression'
8 | },
9 | render: {
10 | compressor: {},
11 | etag: false
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/benchmark/configs/with-etag.js:
--------------------------------------------------------------------------------
1 | import baseConfig from './base'
2 |
3 | export default {
4 | ...baseConfig,
5 | lambda: {
6 | buildDir: '.lambda-with-etag',
7 | distDir: 'dist-with-etag'
8 | },
9 | render: {
10 | compressor: false,
11 | etag: true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/benchmark/configs/with-static.js:
--------------------------------------------------------------------------------
1 | import baseConfig from './base'
2 |
3 | export default {
4 | ...baseConfig,
5 | lambda: {
6 | buildDir: '.lambda-with-static',
7 | distDir: 'dist-with-static',
8 | static: true
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/benchmark/run.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const path = require('path')
4 | const crypto = require('crypto')
5 | const fs = require('fs-extra')
6 | const consola = require('consola')
7 | const execa = require('execa')
8 | const minimist = require('minimist')
9 | const prettyBytes = require('pretty-bytes')
10 | const { NuxtCommand } = require('../lib/utils/nuxt')
11 | const LambdaBuild = require('../lib/build')
12 | // const LambdaTest = require('../lib/test')
13 |
14 | const testCmd = path.resolve(__dirname, '../bin/test-lambda.js')
15 | const rootDir = path.resolve(__dirname, '../example')
16 |
17 | let takeAverageOfRuns = 3
18 |
19 | const configs = [
20 | 'base',
21 | 'with-compression',
22 | 'with-etag',
23 | 'with-static'
24 | ]
25 |
26 | const handlers = [
27 | 'full',
28 | 'connect',
29 | 'minimal'
30 | ]
31 |
32 | const paths = [
33 | '/',
34 | '/about',
35 | '/redirect',
36 | '/nuxt-icon.png'
37 | ]
38 |
39 | function setBuildArgv ({ config, handler, buildNuxt }) {
40 | process.argv = [
41 | 'yarn',
42 | 'nuxt-lambda',
43 | '-c',
44 | path.resolve(__dirname, `configs/${config}.js`),
45 | '--handler',
46 | handler,
47 | buildNuxt ? '' : '--no-nuxt'
48 | ]
49 | }
50 |
51 | function getTestArgs ({ config, pathname }) {
52 | return [
53 | '-c',
54 | path.resolve(__dirname, `configs/${config}.js`),
55 | '--benchmark',
56 | rootDir,
57 | pathname
58 | ]
59 | }
60 |
61 | async function main () {
62 | const argv = minimist(process.argv.slice(2))
63 |
64 | let results
65 | if (argv.results) {
66 | results = require(path.resolve(argv.results))
67 | } else {
68 | if (argv.runs) {
69 | takeAverageOfRuns = parseInt(argv.runs) || takeAverageOfRuns
70 | }
71 |
72 | results = await runBenchmarks()
73 | await fs.outputFile(path.resolve(__dirname, 'results.json'), JSON.stringify(results, null, 2), { encoding: 'utf8' })
74 | }
75 |
76 | const md = createMarkdown(results)
77 | await fs.outputFile(path.resolve(__dirname, '../BENCHMARKS.md'), md, { encoding: 'utf8' })
78 |
79 | consola.info('Benchmarks created')
80 | }
81 |
82 | async function runBenchmarks () {
83 | const results = {}
84 |
85 | for (const config of configs) {
86 | let buildNuxt = true
87 |
88 | for (const handler of handlers) {
89 | setBuildArgv({ config, handler, buildNuxt })
90 | buildNuxt = false
91 |
92 | await NuxtCommand.run(LambdaBuild)
93 |
94 | for (const pathname of paths) {
95 | results[pathname] = results[pathname] || {}
96 | results[pathname][config] = results[pathname][config] || {}
97 |
98 | const takeAverages = []
99 | for (let i = 0; i < takeAverageOfRuns; i++) {
100 | const { stdout } = await execa(testCmd, getTestArgs({ config, pathname }))
101 |
102 | consola.log(pathname, stdout)
103 |
104 | try {
105 | const benchmark = JSON.parse(stdout)
106 |
107 | if (!results[pathname][config][handler]) {
108 | results[pathname][config][handler] = benchmark
109 | }
110 |
111 | takeAverages.push(benchmark)
112 | } catch (err) {
113 | consola.error('Error parsing stdout', stdout)
114 | }
115 | }
116 |
117 | if (takeAverageOfRuns > 1) {
118 | for (const key in results[pathname][config][handler].stats) {
119 | results[pathname][config][handler].stats[key] = Math.round(takeAverages.reduce(
120 | (t, benchmark) => (t += 1 * benchmark.stats[key]),
121 | 0
122 | ) / takeAverageOfRuns)
123 | }
124 |
125 | for (const key in results[pathname][config][handler].mem) {
126 | results[pathname][config][handler].mem[key] = Math.round(takeAverages.reduce(
127 | (t, benchmark) => (t += 1 * benchmark.mem[key]),
128 | 0
129 | ) / takeAverageOfRuns)
130 | }
131 | }
132 | }
133 | }
134 | }
135 |
136 | return results
137 | }
138 |
139 | function createMarkdown (results) {
140 | let markdown = `
141 | # Benchmarks
142 |
143 | > :warning: The total times are measured without downloading & unzipping what normally occures on the AWS platform. Therefore these benchmarks only list _load/parse times_ and not _coldboot times_
144 |
145 | - Times are in \`ms\`
146 | - Times/memory usage are the averages of ${takeAverageOfRuns} runs
147 |
148 | Check the benchmark folder for details how these benchmarks are created
149 |
150 | `
151 |
152 | for (const pathname in results) {
153 | markdown += `## Route \`${pathname}\`\n`
154 |
155 | for (const config in results[pathname]) {
156 | markdown += `### Config _${config}_\n`
157 |
158 | markdown += '|handler|load time|exec time|total time|memory usage|chksum|\n'
159 | markdown += '|---|---|---|---|---|---|\n'
160 |
161 | const responses = {}
162 | for (const handler in results[pathname][config]) {
163 | const result = results[pathname][config][handler]
164 |
165 | const bootTime = prettyHrtime(result.stats.boot)
166 | const execTime = prettyHrtime(result.stats.execute)
167 | const totalTime = prettyHrtime(result.stats.boot + result.stats.execute)
168 | const memUsage = prettyBytes(result.mem.rss)
169 |
170 | const response = JSON.stringify(result.res, null, 2)
171 | responses[handler] = response
172 |
173 | const md5sum = crypto.createHash('md5')
174 | md5sum.update(response)
175 |
176 | markdown += `|_${handler}_|${bootTime}|${execTime}|${totalTime}|${memUsage}|${md5sum.digest('base64')}|\n`
177 | }
178 |
179 | for (const handler in responses) {
180 | markdown += `Response for ${handler}
181 |
182 | \`\`\`js
183 | ${responses[handler].length > 4000 ? 'blob_with_size_' + responses[handler].length : responses[handler]}
184 | \`\`\`
185 |
186 |
187 | `
188 | }
189 | }
190 | }
191 |
192 | return markdown
193 | }
194 |
195 | function prettyHrtime (time) {
196 | return Math.round(time / 1e5) / 10
197 | }
198 |
199 | main()
200 |
--------------------------------------------------------------------------------
/bin/nuxt-lambda.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('../lib/utils/nuxt').NuxtCommand.run(require('../lib/build'))
4 |
--------------------------------------------------------------------------------
/bin/test-lambda.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('../lib/utils/nuxt').NuxtCommand.run(require('../lib/test'))
4 |
--------------------------------------------------------------------------------
/example/assets/nuxt-square.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/example/layouts/default.vue:
--------------------------------------------------------------------------------
1 |
2 |