isolate-package 1.7.1 → 1.8.0-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -246
- package/dist/index.mjs +62 -69
- package/dist/index.mjs.map +1 -1
- package/dist/isolate-bin.mjs +62 -69
- package/dist/isolate-bin.mjs.map +1 -1
- package/docs/lockfiles.md +35 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- TOC -->
|
|
4
4
|
|
|
5
|
+
- [TLDR](#tldr)
|
|
5
6
|
- [Introduction](#introduction)
|
|
6
7
|
- [Features](#features)
|
|
7
8
|
- [Motivation](#motivation)
|
|
8
|
-
- [
|
|
9
|
-
- [Usage
|
|
10
|
-
- [
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Usage](#usage)
|
|
11
|
+
- [Troubleshooting](#troubleshooting)
|
|
11
12
|
- [Prerequisites](#prerequisites)
|
|
12
13
|
- [Define shared dependencies in the package manifest](#define-shared-dependencies-in-the-package-manifest)
|
|
13
14
|
- [Define "version" field in each package manifest](#define-version-field-in-each-package-manifest)
|
|
14
15
|
- [Define "files" field in each package manifest](#define-files-field-in-each-package-manifest)
|
|
15
16
|
- [Use a flat structure inside your packages folders](#use-a-flat-structure-inside-your-packages-folders)
|
|
16
|
-
- [Working with Firebase](#working-with-firebase)
|
|
17
|
-
- [A Quick Start](#a-quick-start)
|
|
18
|
-
- [Deploying from multiple packages](#deploying-from-multiple-packages)
|
|
19
|
-
- [Deploying from the root](#deploying-from-the-root)
|
|
20
17
|
- [Configuration Options](#configuration-options)
|
|
21
18
|
- [buildDirName](#builddirname)
|
|
22
19
|
- [excludeLockfile](#excludelockfile)
|
|
@@ -27,36 +24,38 @@
|
|
|
27
24
|
- [tsconfigPath](#tsconfigpath)
|
|
28
25
|
- [workspacePackages](#workspacepackages)
|
|
29
26
|
- [workspaceRoot](#workspaceroot)
|
|
30
|
-
- [Troubleshooting](#troubleshooting)
|
|
31
27
|
- [Lockfiles](#lockfiles)
|
|
32
|
-
|
|
33
|
-
- [Yarn](#yarn)
|
|
34
|
-
- [A Partial Workaround](#a-partial-workaround)
|
|
35
|
-
- [Different Package Managers](#different-package-managers)
|
|
36
|
-
- [Using the Firebase Functions Emulator](#using-the-firebase-functions-emulator)
|
|
28
|
+
- [API](#api)
|
|
37
29
|
- [The internal packages strategy](#the-internal-packages-strategy)
|
|
30
|
+
- [Working with Firebase](#working-with-firebase)
|
|
31
|
+
- [A Quick Start](#a-quick-start)
|
|
32
|
+
- [Deploying from multiple packages](#deploying-from-multiple-packages)
|
|
33
|
+
- [Deploying from the root](#deploying-from-the-root)
|
|
34
|
+
- [Using the Firebase Functions Emulator](#using-the-firebase-functions-emulator)
|
|
38
35
|
|
|
39
36
|
<!-- /TOC -->
|
|
40
37
|
|
|
38
|
+
## TLDR
|
|
39
|
+
|
|
40
|
+
Run `npx isolate-package isolate` from the monorepo package you would like to
|
|
41
|
+
isolate.
|
|
42
|
+
|
|
41
43
|
## Introduction
|
|
42
44
|
|
|
43
45
|
Isolate a monorepo workspace package to form a self-contained deployable package
|
|
44
46
|
that includes internal dependencies and a compatible lockfile. The internal
|
|
45
|
-
packages structure is preserved
|
|
47
|
+
packages structure is preserved. Code is not bundled.
|
|
46
48
|
|
|
47
49
|
## Features
|
|
48
50
|
|
|
49
|
-
-
|
|
50
|
-
self-contained
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
and PNPM. See [lockfiles](#lockfiles) for more information.
|
|
51
|
+
- Isolates a monorepo package with its internal dependencies to form a
|
|
52
|
+
self-contained deployable directory.
|
|
53
|
+
- Generates an isolated / pruned lockfile based on the existing monorepo
|
|
54
|
+
lockfile. See [lockfiles](#lockfiles) for more information.
|
|
54
55
|
- Zero-config for the vast majority of use-cases, with no manual steps involved.
|
|
55
56
|
- Support for PNPM, NPM and Yarn.
|
|
56
|
-
- Compatible with the Firebase tools CLI, incl 1st
|
|
57
|
-
functions
|
|
58
|
-
- Uses a pack/unpack approach to isolate only those files that would have been
|
|
59
|
-
part of a published NPM package.
|
|
57
|
+
- Compatible with the Firebase tools CLI, incl 1st and 2nd gen Firebase
|
|
58
|
+
functions.
|
|
60
59
|
- Isolates internal workspace dependencies recursively. If package A depends on
|
|
61
60
|
internal package B which depends on internal package C, all of them will be
|
|
62
61
|
included.
|
|
@@ -65,7 +64,7 @@ packages structure is preserved, so dependencies are not bundled.
|
|
|
65
64
|
## Motivation
|
|
66
65
|
|
|
67
66
|
This solution was born from a desire to deploy to
|
|
68
|
-
[Firebase](https://firebase.google.com/) from a monorepo without
|
|
67
|
+
[Firebase](https://firebase.google.com/) from a monorepo without resorting to
|
|
69
68
|
custom shell scripts and other hacks. Here is
|
|
70
69
|
[an article](https://thijs-koerselman.medium.com/deploy-to-firebase-without-the-hacks-e685de39025e)
|
|
71
70
|
explaining the issue in more detail.
|
|
@@ -76,20 +75,19 @@ related to Firebase.
|
|
|
76
75
|
|
|
77
76
|
> !! There is now
|
|
78
77
|
> [a fork of firebase-tools](https://github.com/0x80/firebase-tools-with-isolate),
|
|
79
|
-
> where isolate-package is integrated.
|
|
80
|
-
> setup and allows the isolation to run only as part of the deploy process,
|
|
78
|
+
> where isolate-package is integrated. This is preferred because it simplifies
|
|
79
|
+
> the setup and allows the isolation to run only as part of the deploy process,
|
|
81
80
|
> preserving live code updates when running the local Firebase emulators.
|
|
82
81
|
|
|
83
|
-
##
|
|
82
|
+
## Installation
|
|
84
83
|
|
|
85
|
-
Run `pnpm install isolate-package --dev` or the equivalent for `
|
|
84
|
+
Run `pnpm install isolate-package --dev` or the equivalent for `npm` or `yarn`.
|
|
86
85
|
|
|
87
86
|
I recommend using `pnpm` for
|
|
88
|
-
[a number of reasons](https://pnpm.io/feature-comparison).
|
|
89
|
-
|
|
90
|
-
lockfile. For more information see [lockfiles](#lockfiles).
|
|
87
|
+
[a number of reasons](https://pnpm.io/feature-comparison). In my experience it
|
|
88
|
+
is the best package manager, especially for monorepo setups.
|
|
91
89
|
|
|
92
|
-
## Usage
|
|
90
|
+
## Usage
|
|
93
91
|
|
|
94
92
|
This package exposes a binary called `isolate`.
|
|
95
93
|
|
|
@@ -105,21 +103,18 @@ By default the isolated output will become available at `./isolate`.
|
|
|
105
103
|
If you are here to simplify and improve your Firebase deployments check out the
|
|
106
104
|
[Firebase quick start guide](#a-quick-start).
|
|
107
105
|
|
|
108
|
-
##
|
|
106
|
+
## Troubleshooting
|
|
109
107
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
different location as the standard `node:console`.
|
|
108
|
+
If something is not working as expected, add a `isolate.config.json` file, and
|
|
109
|
+
set `"logLevel"` to `"debug"`. This should give you detailed feedback in the
|
|
110
|
+
console.
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
In addition define an environment variable to debug the configuration being used
|
|
113
|
+
by setting `DEBUG_ISOLATE_CONFIG=true` before you execute `isolate`.
|
|
117
114
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
122
|
-
```
|
|
115
|
+
When debugging Firebase deployment issues it might be convenient to trigger the
|
|
116
|
+
isolate process manually with `npx isolate` and possibly
|
|
117
|
+
`DEBUG_ISOLATE_CONFIG=true npx isolate`
|
|
123
118
|
|
|
124
119
|
If you do not pass in any configuration, the function will try to read a
|
|
125
120
|
`isolate.config.json` file from disk. You can set
|
|
@@ -163,10 +158,9 @@ generate part of the packed filename. A personal preference is to set it to
|
|
|
163
158
|
|
|
164
159
|
### Define "files" field in each package manifest
|
|
165
160
|
|
|
166
|
-
> NOTE: This step is not required if you use the
|
|
167
|
-
>
|
|
168
|
-
>
|
|
169
|
-
> > instead of `["dist"]`.
|
|
161
|
+
> NOTE: This step is not required if you use the
|
|
162
|
+
> [internal packages strategy](#the-internal-packages-strategy) but you could
|
|
163
|
+
> set it to `["src"]` instead of `["dist"]`.
|
|
170
164
|
|
|
171
165
|
The isolate process uses (p)npm `pack` to extract files from package
|
|
172
166
|
directories, just like publishing a package would.
|
|
@@ -207,112 +201,6 @@ You can, however, declare multiple workspace packages directories. Personally, I
|
|
|
207
201
|
prefer to use `["packages/*", "apps/*", "services/*"]`. It is only the structure
|
|
208
202
|
inside them that should be flat.
|
|
209
203
|
|
|
210
|
-
## Working with Firebase
|
|
211
|
-
|
|
212
|
-
> !! There is now
|
|
213
|
-
> [a fork of firebase-tools](https://github.com/0x80/firebase-tools-with-isolate),
|
|
214
|
-
> where isolate-package is integrated. It is preferred because it simplifies the
|
|
215
|
-
> setup and allows the isolation to run only as part of the deploy process,
|
|
216
|
-
> preserving live code updates when running the local Firebase emulators.
|
|
217
|
-
|
|
218
|
-
### A Quick Start
|
|
219
|
-
|
|
220
|
-
If you are not confident that your monorepo setup is solid, please check out my
|
|
221
|
-
in-dept example at [mono-ts](https://github.com/0x80/mono-ts) where many
|
|
222
|
-
different aspects are discussed and `isolate-package` is used to demonstrate
|
|
223
|
-
Firebase deployments.
|
|
224
|
-
|
|
225
|
-
This section describes the steps required for Firebase deployment, assuming:
|
|
226
|
-
|
|
227
|
-
- You use a fairly typical monorepo setup
|
|
228
|
-
- Your `firebase.json` config lives in the root of the package that you like to
|
|
229
|
-
deploy to Firebase, hereafter referred to as the "target package".
|
|
230
|
-
|
|
231
|
-
If your setup diverges from a traditional one, please continue reading the
|
|
232
|
-
[Prerequisites](#prerequisites) section.
|
|
233
|
-
|
|
234
|
-
1. In the target package, install `isolate-package` and `firebase-tools` by
|
|
235
|
-
running `pnpm add isolate-package firebase-tools -D` or the Yarn / NPM
|
|
236
|
-
equivalent. I tend to install firebase-tools as a devDependency in every
|
|
237
|
-
Firebase package, but you could also use a global install if you prefer that.
|
|
238
|
-
2. In the `firebase.json` config set `"source"` to `"./isolate"` and
|
|
239
|
-
`"predeploy"` to `["turbo build", "isolate"]` or whatever suits your build
|
|
240
|
-
tool. The important part here is that isolate is being executed after the
|
|
241
|
-
build stage.
|
|
242
|
-
3. From the target package folder, you should now be able to deploy with
|
|
243
|
-
`npx firebase deploy`.
|
|
244
|
-
|
|
245
|
-
I recommend keeping a `firebase.json` file inside each Firebase package (as
|
|
246
|
-
opposed to the monorepo root), because it allows you to deploy from multiple
|
|
247
|
-
independent packages. It makes it easy to deploy 1st gen functions next to 2nd
|
|
248
|
-
gen functions, deploy different node versions, and decrease the built output
|
|
249
|
-
size and dependency lists for each package, improving deployment and cold-start
|
|
250
|
-
times.
|
|
251
|
-
|
|
252
|
-
### Deploying from multiple packages
|
|
253
|
-
|
|
254
|
-
You can deploy to Firebase from multiple packages in your monorepo, in which
|
|
255
|
-
case you co-locate your `firebase.json` file with the source code, and not in
|
|
256
|
-
the root of the monorepo. If you do want to keep the firebase config in the
|
|
257
|
-
root, read the instructions for
|
|
258
|
-
[deploying to Firebase from the root](#deploying-to-firebase-from-the-root).
|
|
259
|
-
|
|
260
|
-
In order to deploy to Firebase, the `functions.source` setting in
|
|
261
|
-
`firebase.json` needs to point to the isolated output folder, which would be
|
|
262
|
-
`./isolate` when using the default configuration.
|
|
263
|
-
|
|
264
|
-
The `predeploy` phase should first build and then isolate the output.
|
|
265
|
-
|
|
266
|
-
Here's an example using [Turborepo](https://turbo.build/):
|
|
267
|
-
|
|
268
|
-
```cjson
|
|
269
|
-
// firebase.json
|
|
270
|
-
{
|
|
271
|
-
"functions": {
|
|
272
|
-
"source": "./isolate",
|
|
273
|
-
"predeploy": ["turbo build", "isolate"]
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
With this configuration you can then run `npx firebase deploy --only functions`
|
|
279
|
-
from the package.
|
|
280
|
-
|
|
281
|
-
If you like to deploy to Firebase Functions from multiple packages you will also
|
|
282
|
-
need to configure a unique `codebase` identifier for each of them. For more
|
|
283
|
-
information,
|
|
284
|
-
[read this](https://firebase.google.com/docs/functions/beta/organize-functions).
|
|
285
|
-
|
|
286
|
-
Make sure your Firebase package adheres to the things mentioned in
|
|
287
|
-
[prerequisites](#prerequisites) and its package manifest contains the field
|
|
288
|
-
`"main"`, or `"module"` if you set `"type": "module"`, so Firebase knows the
|
|
289
|
-
entry point to your source code.
|
|
290
|
-
|
|
291
|
-
### Deploying from the root
|
|
292
|
-
|
|
293
|
-
If, for some reason, you choose to keep the `firebase.json` file in the root of
|
|
294
|
-
the monorepo you will have to place a configuration file called
|
|
295
|
-
`isolate.config.json` in the root with the following content:
|
|
296
|
-
|
|
297
|
-
```cjson
|
|
298
|
-
// isolate.config.json
|
|
299
|
-
{
|
|
300
|
-
"targetPackagePath": "./packages/your-firebase-package"
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
The Firebase configuration should then look something like this:
|
|
305
|
-
|
|
306
|
-
```cjson
|
|
307
|
-
// firebase.json
|
|
308
|
-
{
|
|
309
|
-
"functions": {
|
|
310
|
-
"source": "./packages/your-firebase-package/isolate",
|
|
311
|
-
"predeploy": ["turbo build", "isolate"]
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
204
|
## Configuration Options
|
|
317
205
|
|
|
318
206
|
For most users no configuration should be necessary.
|
|
@@ -338,13 +226,16 @@ setting to specify where the build output files are located.
|
|
|
338
226
|
|
|
339
227
|
Type: `boolean`, default: Depends on package manager.
|
|
340
228
|
|
|
229
|
+
**Deprecated** This option exists from the time that lockfiles were not
|
|
230
|
+
supported for all package managers. You should not need this escape hatch
|
|
231
|
+
anymore.
|
|
232
|
+
|
|
341
233
|
Sets the inclusion or exclusion of the lockfile as part of the deployment.
|
|
342
234
|
|
|
343
|
-
Isolated
|
|
344
|
-
lockfile, and they are included by default.
|
|
235
|
+
Isolated / pruned lockfiles are generated for NPM, PNPM and Yarn v1 (classic)
|
|
236
|
+
based on the existing root lockfile, and they are included by default.
|
|
345
237
|
|
|
346
|
-
|
|
347
|
-
[lockfiles](#lockfiles).
|
|
238
|
+
For more information see [lockfiles](#lockfiles).
|
|
348
239
|
|
|
349
240
|
### includeDevDependencies
|
|
350
241
|
|
|
@@ -430,83 +321,191 @@ services
|
|
|
430
321
|
|
|
431
322
|
When you use the `targetPackagePath` option, this setting will be ignored.
|
|
432
323
|
|
|
433
|
-
##
|
|
324
|
+
## Lockfiles
|
|
434
325
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
console.
|
|
326
|
+
A lockfile in a monorepo describes the dependencies of all packages, and does
|
|
327
|
+
not translate to the isolated output without altering it.
|
|
438
328
|
|
|
439
|
-
|
|
440
|
-
|
|
329
|
+
If you copying the original lockfile and deploy it with the isolated code, a CI
|
|
330
|
+
environment will not accept the lockfile. It is also not possibly to generate a
|
|
331
|
+
brand new lockfile from the isolated code by mimicking a fresh install, because
|
|
332
|
+
versions would be able to diverge and thus negate the whole point of having a
|
|
333
|
+
lockfile in the first place.
|
|
441
334
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
335
|
+
For this to work, we need to re-generate or prune the original lockfile to keep
|
|
336
|
+
the versions of the original but only describe the dependencies of the code in
|
|
337
|
+
the isolated output.
|
|
445
338
|
|
|
446
|
-
|
|
339
|
+
Since every package manager works completely different in this regard, this part
|
|
340
|
+
of the puzzle had to be solved in a different ways for each of them, and not all
|
|
341
|
+
are supported yet.
|
|
447
342
|
|
|
448
|
-
|
|
449
|
-
not necessarily translate to the isolated output without altering it. Different
|
|
450
|
-
package managers use very different formats, and it might not be enough to do a
|
|
451
|
-
find/replace on some paths.
|
|
343
|
+
At the moment lockfiles for the following package managers are supported:
|
|
452
344
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
345
|
+
- NPM
|
|
346
|
+
- PNPM
|
|
347
|
+
- Yarn Classic (v1)
|
|
456
348
|
|
|
457
|
-
|
|
458
|
-
|
|
349
|
+
More detailed information on the implementation can be found in the
|
|
350
|
+
[additional docs](./docs/lockfiles.md).
|
|
459
351
|
|
|
460
|
-
|
|
352
|
+
## API
|
|
461
353
|
|
|
462
|
-
|
|
354
|
+
Alternatively, `isolate` can be integrated in other programs by importing it as
|
|
355
|
+
a function. You optionally pass it a some user configuration and possibly a
|
|
356
|
+
logger to handle any output messages should you need to write them to a
|
|
357
|
+
different location as the standard `node:console`.
|
|
463
358
|
|
|
464
|
-
|
|
359
|
+
```ts
|
|
360
|
+
import { isolate } from "isolate-package";
|
|
465
361
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
362
|
+
await isolate({
|
|
363
|
+
config: { logLevel: "debug" },
|
|
364
|
+
logger: customLogger,
|
|
365
|
+
});
|
|
366
|
+
```
|
|
469
367
|
|
|
470
|
-
|
|
368
|
+
## The internal packages strategy
|
|
369
|
+
|
|
370
|
+
An alternative approach to using internal dependencies in a Typescript monorepo
|
|
371
|
+
is
|
|
372
|
+
[the internal packages strategy](https://turbo.build/blog/you-might-not-need-typescript-project-references),
|
|
373
|
+
in which the package manifest entries point directly to Typescript source files,
|
|
374
|
+
to omit intermediate build steps. The approach is compatible with
|
|
375
|
+
isolate-package and showcased in
|
|
376
|
+
[my example monorepo setup](https://github.com/0x80/mono-ts)
|
|
377
|
+
|
|
378
|
+
In summary this is how it works:
|
|
471
379
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
380
|
+
1. The package to be deployed lists its internal dependencies as usual, but the
|
|
381
|
+
package manifests of those dependencies point directly to the Typescript
|
|
382
|
+
source (and types).
|
|
383
|
+
2. You configure the bundler of your target package to include the source code
|
|
384
|
+
for those internal packages in its output bundle. In the case of TSUP for the
|
|
385
|
+
[API service in the mono-ts](https://github.com/0x80/mono-ts/blob/main/services/api/tsup.config.ts)
|
|
386
|
+
that configuration is: `noExternal: ["@mono/common"]`
|
|
387
|
+
3. When `isolate` runs, it does the same thing as always. It detects the
|
|
388
|
+
internal packages, copies them to the isolate output folder and adjusts any
|
|
389
|
+
links.
|
|
390
|
+
4. When deploying to Firebase, the cloud pipeline will treat the package
|
|
391
|
+
manifest as usual, which installs the listed dependencies and any
|
|
392
|
+
dependencies listed in the linked internal package manifests.
|
|
393
|
+
|
|
394
|
+
Steps 3 and 4 are no different from a traditional setup.
|
|
395
|
+
|
|
396
|
+
Note that the manifests for the internal packages in the output will still point
|
|
397
|
+
to the Typescript source files, but since the shared code was embedded in the
|
|
398
|
+
bundle, they will never be referenced via import statements. So the manifest the
|
|
399
|
+
entry declarations are never used. The reason the packages are included in the
|
|
400
|
+
isolated output is to instruct package manager to install their dependencies.
|
|
401
|
+
|
|
402
|
+
## Working with Firebase
|
|
403
|
+
|
|
404
|
+
> !! There is now
|
|
405
|
+
> [a fork of firebase-tools](https://github.com/0x80/firebase-tools-with-isolate),
|
|
406
|
+
> where isolate-package is integrated. This is preferred because it simplifies
|
|
407
|
+
> the setup and allows the isolation to run only as part of the deploy process,
|
|
408
|
+
> preserving live code updates when running the local Firebase emulators.
|
|
475
409
|
|
|
476
|
-
|
|
477
|
-
deployment by setting `"excludeLockfile": false` in your isolate.config.json
|
|
478
|
-
file, or make the move to PNPM (recommended).
|
|
410
|
+
### A Quick Start
|
|
479
411
|
|
|
480
|
-
|
|
481
|
-
|
|
412
|
+
If you are not confident that your monorepo setup is solid, please check out my
|
|
413
|
+
in-dept example at [mono-ts](https://github.com/0x80/mono-ts) where many
|
|
414
|
+
different aspects are discussed and `isolate-package` is used to demonstrate
|
|
415
|
+
Firebase deployments.
|
|
482
416
|
|
|
483
|
-
|
|
484
|
-
personally recommend switching to PNPM.
|
|
417
|
+
This section describes the steps required for Firebase deployment, assuming:
|
|
485
418
|
|
|
486
|
-
|
|
419
|
+
- You use a fairly typical monorepo setup
|
|
420
|
+
- Your `firebase.json` config lives in the root of the package that you like to
|
|
421
|
+
deploy to Firebase, hereafter referred to as the "target package".
|
|
487
422
|
|
|
488
|
-
If
|
|
489
|
-
|
|
490
|
-
This doesn't prevent your dependencies-dependencies from installing newer
|
|
491
|
-
versions, like a lockfile would, but at least you minimize the risk of things
|
|
492
|
-
breaking.
|
|
423
|
+
If your setup diverges from a traditional one, please continue reading the
|
|
424
|
+
[Prerequisites](#prerequisites) section.
|
|
493
425
|
|
|
494
|
-
|
|
426
|
+
1. In the target package, install `isolate-package` and `firebase-tools` by
|
|
427
|
+
running `pnpm add isolate-package firebase-tools -D` or the Yarn / NPM
|
|
428
|
+
equivalent. I tend to install firebase-tools as a devDependency in every
|
|
429
|
+
Firebase package, but you could also use a global install if you prefer that.
|
|
430
|
+
2. In the `firebase.json` config set `"source"` to `"./isolate"` and
|
|
431
|
+
`"predeploy"` to `["turbo build", "isolate"]` or whatever suits your build
|
|
432
|
+
tool. The important part here is that isolate is being executed after the
|
|
433
|
+
build stage.
|
|
434
|
+
3. From the target package folder, you should now be able to deploy with
|
|
435
|
+
`npx firebase deploy`.
|
|
495
436
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
437
|
+
I recommend keeping a `firebase.json` file inside each Firebase package (as
|
|
438
|
+
opposed to the monorepo root), because it allows you to deploy from multiple
|
|
439
|
+
independent packages. It makes it easy to deploy 1st gen functions next to 2nd
|
|
440
|
+
gen functions, deploy different node versions, and decrease the built output
|
|
441
|
+
size and dependency lists for each package, improving deployment and cold-start
|
|
442
|
+
times.
|
|
499
443
|
|
|
500
|
-
|
|
501
|
-
type of lockfile found and the version that the OS reports for the installed
|
|
502
|
-
executable. This information is then used to change some of its behavior. For
|
|
503
|
-
example, the PNPM `pack` process is preferred over the default NPM `pack` if
|
|
504
|
-
PNPM in used, simply because it seems to be much faster.
|
|
444
|
+
### Deploying from multiple packages
|
|
505
445
|
|
|
506
|
-
|
|
507
|
-
|
|
446
|
+
You can deploy to Firebase from multiple packages in your monorepo, in which
|
|
447
|
+
case you co-locate your `firebase.json` file with the source code, and not in
|
|
448
|
+
the root of the monorepo. If you do want to keep the firebase config in the
|
|
449
|
+
root, read the instructions for
|
|
450
|
+
[deploying to Firebase from the root](#deploying-to-firebase-from-the-root).
|
|
508
451
|
|
|
509
|
-
|
|
452
|
+
In order to deploy to Firebase, the `functions.source` setting in
|
|
453
|
+
`firebase.json` needs to point to the isolated output folder, which would be
|
|
454
|
+
`./isolate` when using the default configuration.
|
|
455
|
+
|
|
456
|
+
The `predeploy` phase should first build and then isolate the output.
|
|
457
|
+
|
|
458
|
+
Here's an example using [Turborepo](https://turbo.build/):
|
|
459
|
+
|
|
460
|
+
```cjson
|
|
461
|
+
// firebase.json
|
|
462
|
+
{
|
|
463
|
+
"functions": {
|
|
464
|
+
"source": "./isolate",
|
|
465
|
+
"predeploy": ["turbo build", "isolate"]
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
With this configuration you can then run `npx firebase deploy --only functions`
|
|
471
|
+
from the package.
|
|
472
|
+
|
|
473
|
+
If you like to deploy to Firebase Functions from multiple packages you will also
|
|
474
|
+
need to configure a unique `codebase` identifier for each of them. For more
|
|
475
|
+
information,
|
|
476
|
+
[read this](https://firebase.google.com/docs/functions/beta/organize-functions).
|
|
477
|
+
|
|
478
|
+
Make sure your Firebase package adheres to the things mentioned in
|
|
479
|
+
[prerequisites](#prerequisites) and its package manifest contains the field
|
|
480
|
+
`"main"`, or `"module"` if you set `"type": "module"`, so Firebase knows the
|
|
481
|
+
entry point to your source code.
|
|
482
|
+
|
|
483
|
+
### Deploying from the root
|
|
484
|
+
|
|
485
|
+
If, for some reason, you choose to keep the `firebase.json` file in the root of
|
|
486
|
+
the monorepo you will have to place a configuration file called
|
|
487
|
+
`isolate.config.json` in the root with the following content:
|
|
488
|
+
|
|
489
|
+
```cjson
|
|
490
|
+
// isolate.config.json
|
|
491
|
+
{
|
|
492
|
+
"targetPackagePath": "./packages/your-firebase-package"
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
The Firebase configuration should then look something like this:
|
|
497
|
+
|
|
498
|
+
```cjson
|
|
499
|
+
// firebase.json
|
|
500
|
+
{
|
|
501
|
+
"functions": {
|
|
502
|
+
"source": "./packages/your-firebase-package/isolate",
|
|
503
|
+
"predeploy": ["turbo build", "isolate"]
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Using the Firebase Functions Emulator
|
|
510
509
|
|
|
511
510
|
The Firebase functions emulator runs on the code that firebase.json `source`
|
|
512
511
|
points to. Unfortunately, this is the same field as is used for declaring the
|
|
@@ -531,37 +530,3 @@ deployment process and the `source` property can still point to the original
|
|
|
531
530
|
code.
|
|
532
531
|
|
|
533
532
|
I plan to work on this once isolate-package is bit more mature.
|
|
534
|
-
|
|
535
|
-
## The internal packages strategy
|
|
536
|
-
|
|
537
|
-
Recently I changed [my example monorepo setup](https://github.com/0x80/mono-ts)
|
|
538
|
-
to include
|
|
539
|
-
[the internal packages strategy](https://turbo.build/blog/you-might-not-need-typescript-project-references),
|
|
540
|
-
(in which the package manifest entries point directly to TS source files, to
|
|
541
|
-
omit the build step), and I was pleased to discover that the approach is
|
|
542
|
-
compatible with `isolate-packages` with only a single change in configuration.
|
|
543
|
-
|
|
544
|
-
In summary this is how it works:
|
|
545
|
-
|
|
546
|
-
1. The package to be deployed lists its internal dependencies as usual, but the
|
|
547
|
-
package manifests of those dependencies point directly to the Typescript
|
|
548
|
-
source (and types).
|
|
549
|
-
2. You configure the bundler of your target package to include the source code
|
|
550
|
-
for those internal packages in its output bundle. In the case of TSUP for the
|
|
551
|
-
[API service in the mono-ts](https://github.com/0x80/mono-ts/blob/main/services/api/tsup.config.ts)
|
|
552
|
-
that configuration is: `noExternal: ["@mono/common"]`
|
|
553
|
-
3. When `isolate` runs, it does the exact same thing as always. It will detect
|
|
554
|
-
the internal packages, copies them to the isolate output folder and adjusts
|
|
555
|
-
any links.
|
|
556
|
-
4. When deploying to Firebase, the cloud pipeline will treat the package
|
|
557
|
-
manifest as usual, which installs the listed dependencies and any
|
|
558
|
-
dependencies listed in the linked internal package manifests.
|
|
559
|
-
|
|
560
|
-
Steps 3 and 4 are no different from a traditional setup.
|
|
561
|
-
|
|
562
|
-
Note that the manifests for the internal packages will still point to the
|
|
563
|
-
Typescript source files, but since the shared code was embedded in the deployed
|
|
564
|
-
bundle, they will never be referenced via import statements and as a result the
|
|
565
|
-
entry points remain unused. The only reason the packages are included in the
|
|
566
|
-
isolated output is so that the package manager knows what dependencies to
|
|
567
|
-
install.
|