-
Notifications
You must be signed in to change notification settings - Fork 246
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 jsii modules as npm tarballs #52
Conversation
This change modifies the way we bundle jsii modules. Instead of webpacking them and storing the code inside the assembly spec, we now simply use "npm pack" to produce an npm tarball (.tgz) and include that in the generated library. The kernel now simply accepts the path to the tarball (as oppose to the entire code passed through STDIN), and untars it into a working directory (under node_modules). This effectively allows dependencies to `require(it)`. This change also dramatically improves load-time performance (again, we are not sending a big JSON file over the wire, parse it, and then evaluate it into the VM). Bundled dependencies are now simple npm bundled dependencies. If a module uses the old- style configuration, we fail with instructions. NOTE: we currently do not support multiple versions of the same module loaded together into the same kernel space. This is a major and unacceptable limitation for production environments, which we must address, or otherwise, people will constantly hit these restrictions as jsii software stacks evolve. BREAKING CHANGE.
.gitignore
Outdated
@@ -348,6 +348,7 @@ jspm_packages/ | |||
|
|||
# Output of 'npm pack' | |||
*.tgz | |||
!*.jsii.tgz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to check in tarballs? Why not ignore them at the .npmignore
level instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, thats obviously a mistake
packages/jsii-kernel/lib/api.ts
Outdated
@@ -27,7 +27,17 @@ export interface HelloResponse { | |||
} | |||
|
|||
export interface LoadRequest { | |||
assembly: Assembly; | |||
/** @deprecated */ | |||
assembly?: Assembly; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we throw an error if assembly
is present, is deprecated
the right semantics? I think it would be better to remove the assembly
property altogether (and continue to throw an error if it is present).
packages/jsii-kernel/lib/kernel.ts
Outdated
@@ -211,7 +274,9 @@ export class Kernel { | |||
return this._wrapSandboxCode(() => fn.apply(obj, this._toSandboxValues(args))); | |||
}); | |||
|
|||
this._debug('method returned:', ret); | |||
// console.error(ret); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented code
@@ -47,41 +47,64 @@ export interface IGenerator | |||
*/ | |||
export abstract class Generator implements IGenerator { | |||
private readonly options: GeneratorOptions; | |||
private readonly mod: spec.Assembly | |||
private mod: spec.Assembly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: More readable to use the full word module
. More broadly, it isn't clear what the difference is between modules and assemblies. If there is no difference, we should use the same terminology everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got rid of .mod
/** | ||
* Runs the generator (in-memory). | ||
*/ | ||
generate() { | ||
this.onBeginAssembly(this.mod); | ||
this.visit(this.mod.nametree); | ||
if (this.mod.nametree) { | ||
this.visit(this.mod.nametree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we deprecated nametree
. If not, we should update http://sapp.amazon.com/jsii/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I need to update the spec :-)
[please try to avoid using non-public URLs here]
update-version.sh
Outdated
@@ -1,4 +1,5 @@ | |||
#!/bin/bash | |||
set -e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be set -euo pipefail
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
Bundle jsii tarball modules into generated .NET packages and also bundle the jsii-runtime program as an embedded resource into the dotnet runtime library. This removes the dependency on jsii-runtime, and leaves only node.js as an external dependency. It also improves load-time performance since the tarball is only passed as a path to the runtime/kernel and not the entire .js code.
`set -euo` fails for unbound variables
Since we have version numbers in test expectations every build will get a different version number and that invariably causes tests to fail.
1. Add calc-lib 2. Create expected tarball on-the-fly to avoid binary diffs resulting from different platforms
|
||
const generatorClass: any = await lookupGenerator(lang); | ||
return new generatorClass(mod); | ||
const tarball = await npmPack(packageDir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we always pack? Is this relevant, for example when we generate docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KISS
await generator.save(outDir); | ||
} | ||
async function npmPack(packageDir: string) { | ||
const child = spawn('npm', [ 'pack', '--ignore-scripts' ], { cwd: packageDir, stdio: [ 'ignore', 'pipe', 'pipe' ] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this should --ignore-scripts
here; as this no longer guarantees reproductible outcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I need to think about it, also how this interplays with cross-language builds and publishing (#73)
const tarball = await new Promise<string>((ok, fail) => { | ||
let stdout = ''; | ||
let stderr = ''; | ||
child.stdout.on('data', chunk => stdout += chunk.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unsafe to do: the chunks may include incomplete multi-byte characters (the rest could be in the next chunk), which could render the stdout
and stderr
strings invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm.. Good to know. I will change to Buffer.concat
.
return ok(stdout.trim()); | ||
} else { | ||
process.stderr.write(stderr); | ||
return fail(new Error('Exit with status ' + status)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
status
might be null
, if the child is killed by a signal.
This change modifies the way we bundle jsii modules. Instead of webpacking them
and storing the code inside the assembly spec, we now simply use "npm pack" to
produce an npm tarball (.tgz) and include that in the generated library.
The kernel now simply accepts the path to the tarball (as oppose to the entire
code passed through STDIN), and untars it into a working directory (under node_modules).
This effectively allows dependencies to
require(it)
.Bundled dependencies are now simple npm bundled dependencies. If a module uses the old-
style configuration, we fail with instructions.
PERF: This change also improves load-time performance (again, we are not sending
a big JSON file over the wire, parse it, and then evaluate it into the VM).
.NET: Furthermore, in .NET we didn't even bundle the webpack and the jsii-runtime, so this change includes modifications to the .NET generator and runtime to actually bundle the runtime and the new tarballs. This removes the dependency on jsii-runtime for .NET, and leaves only node.js as an external dependency.
NOTE ABOUT VERSIONS: we currently do not support multiple versions of the same module loaded together into the same kernel space. This is a major and unacceptable limitation for production
environments, which we must address, or otherwise, people will constantly hit these
restrictions as jsii software stacks evolve.
BREAKING CHANGE