github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/codegen/nodejs/gen_lazyloads.go (about) 1 // Copyright 2016-2022, Pulumi Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Large providers like azure-native generate code that has a high 16 // startup overhead in Node JS due to loading thousands of modules at 17 // once. The code in this file is dedicated to support on-demand 18 // (lazy) loading of modules at Node level to speed up program 19 // startup. 20 21 package nodejs 22 23 import ( 24 "encoding/json" 25 "fmt" 26 "io" 27 "sort" 28 "strings" 29 30 "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" 31 ) 32 33 type lazyLoadGen struct{} 34 35 func newLazyLoadGen() *lazyLoadGen { 36 return &lazyLoadGen{} 37 } 38 39 // Generates TypeScript code to re-export a generated module. For 40 // resources and functions this is optimized to use lazy loading. 41 // Falls back to eager re-export for everything else. 42 func (ll *lazyLoadGen) genReexport(w io.Writer, exp fileInfo, importPath string) { 43 if exp.fileType == functionFileType { 44 // optimize lazy-loading function modules 45 ll.genFunctionReexport(w, exp.functionFileInfo, importPath) 46 } else if exp.fileType == resourceFileType { 47 // optimize lazy-loading resource modules 48 ll.genResourceReexport(w, exp.resourceFileInfo, importPath) 49 } else { 50 // non-optimized but foolproof eager reexport 51 fmt.Fprintf(w, "export * from %q;\n", importPath) 52 } 53 } 54 55 // Used as a follow up to multiple genReexport calls to generate a 56 // lazy-load polyfill to all the properties that need that. 57 func (*lazyLoadGen) genLazyLoads(w io.Writer, importPath string, properties ...string) { 58 sort.Strings(properties) 59 j, err := json.Marshal(properties) 60 contract.AssertNoError(err) 61 fmt.Fprintf(w, "utilities.lazyLoad(exports, %s, () => require(%q));\n", 62 string(j), importPath) 63 } 64 65 // Generates TypeScript code that lazily imports and re-exports a 66 // module defining a resource, while also importing the resoure class 67 // in-scope. Needs to know which names the module defines 68 // (resourceFileInfo). 69 func (ll *lazyLoadGen) genResourceReexport(w io.Writer, i resourceFileInfo, importPath string) { 70 defer fmt.Fprintf(w, "\n") 71 72 quotedImport := fmt.Sprintf("%q", importPath) 73 74 // not sure how to lazy-load in presence of re-exported 75 // namespaces; bail and use an eager load in this case; also 76 // eager-import the class. 77 if i.methodsNamespaceName != "" { 78 fmt.Fprintf(w, "export * from %s;\n", quotedImport) 79 fmt.Fprintf(w, "import { %s } from %s;\n", i.resourceClassName, quotedImport) 80 return 81 } 82 83 // Re-export interfaces. This is type-only and does not 84 // generate a require() call. 85 fmt.Fprintf(w, "export { %s } from %s;\n", 86 strings.Join(i.interfaces(), ", "), 87 quotedImport) 88 89 // Re-export class type into the type group, see 90 // https://www.typescriptlang.org/docs/handbook/declaration-merging.html 91 fmt.Fprintf(w, "export type %[1]s = import(%[2]s).%[1]s;\n", 92 i.resourceClassName, 93 quotedImport) 94 95 // Mock re-export class value into the value group - for compilation. 96 fmt.Fprintf(w, "export const %[1]s: typeof import(%[2]s).%[1]s = null as any;\n", 97 i.resourceClassName, 98 quotedImport) 99 100 ll.genLazyLoads(w, importPath, i.resourceClassName) 101 } 102 103 // Generates TypeScript code that lazily imports and re-exports a 104 // module defining a function. Needs to which names the module defines 105 // (functionFileInfo). 106 func (ll *lazyLoadGen) genFunctionReexport(w io.Writer, i functionFileInfo, importPath string) { 107 defer fmt.Fprintf(w, "\n") 108 109 quotedImport := fmt.Sprintf("%q", importPath) 110 111 // Re-export interfaces. This is type-only and does not 112 // generate a require() call. 113 interfaces := i.interfaces() 114 if len(interfaces) > 0 { 115 fmt.Fprintf(w, "export { %s } from %s;\n", 116 strings.Join(interfaces, ", "), 117 quotedImport) 118 } 119 120 // Re-export function values into the value group, and install lazy loading. 121 funcs := i.functions() 122 for _, f := range funcs { 123 fmt.Fprintf(w, "export const %[1]s: typeof import(%[2]s).%[1]s = null as any;\n", 124 f, quotedImport) 125 } 126 ll.genLazyLoads(w, importPath, funcs...) 127 }