diff --git a/entc/gen/feature.go b/entc/gen/feature.go index 0e47195ad6..97f154136a 100644 --- a/entc/gen/feature.go +++ b/entc/gen/feature.go @@ -159,6 +159,30 @@ var ( }, } + // FeatureNoClientSchema keeps the migration engine off the generated + // Client, so that a binary which never migrates does not link it. + // + // `Client.Schema` is a `*migrate.Schema`, and `NewClient` builds one. That + // is an import, and the linker follows imports: the generated package pulls + // in `dialect/sql/schema`, which pulls in Atlas -- its diff planner, all + // three of its SQL dialects, and the HCL parser those import for a schema + // language most programs never write. Measured on one app compiled to + // `GOOS=js GOARCH=wasm`, that was 10.5 MB of a 57 MB module, linked to + // answer a question the program does not ask. + // + // With this on, `Client` has no `Schema` field and the caller says it: + // + // migrate.NewSchema(drv).Create(ctx) + // + // which needs the driver it already had to build the client. `migrate` is + // generated either way, so a program that does migrate is unaffected. + FeatureNoClientSchema = Feature{ + Name: "sql/no-client-schema", + Stage: Experimental, + Default: false, + Description: "Keeps the migration engine off the generated Client, so a binary that never migrates does not link it", + } + // AllFeatures holds a list of all feature-flags. AllFeatures = []Feature{ FeaturePrivacy, @@ -174,6 +198,7 @@ var ( FeatureUpsert, FeatureVersionedMigration, FeatureGlobalId, + FeatureNoClientSchema, } // allFeatures includes all public and private features. allFeatures = append(AllFeatures, featureMultiSchema) diff --git a/entc/gen/template/client.tmpl b/entc/gen/template/client.tmpl index d1dc249db2..cc3dfb5983 100644 --- a/entc/gen/template/client.tmpl +++ b/entc/gen/template/client.tmpl @@ -10,7 +10,7 @@ in the LICENSE file in the root directory of this source tree. // Client is the client that holds all ent builders. type Client struct { config - {{- if $.SupportMigrate }} + {{- if and $.SupportMigrate (not ($.FeatureEnabled "sql/no-client-schema")) }} // Schema is the client for creating, migrating and dropping schema. Schema *migrate.Schema {{- end }} @@ -34,7 +34,7 @@ func NewClient(opts ...Option) *Client { } func (c *Client) init() { - {{- if $.SupportMigrate }} + {{- if and $.SupportMigrate (not ($.FeatureEnabled "sql/no-client-schema")) }} c.Schema = migrate.NewSchema(c.driver) {{- end }} {{- range $n := $.Nodes }} @@ -55,7 +55,9 @@ import ( "context" "log" + {{- if not ($.FeatureEnabled "sql/no-client-schema") }} "{{ $.Config.Package }}/migrate" + {{- end }} {{ range $n := $.Nodes }} {{ $n.PackageAlias }} "{{ $n.Config.Package }}/{{ $n.PackageDir }}" {{- end }} diff --git a/entc/gen/template/enttest.tmpl b/entc/gen/template/enttest.tmpl index fe25723282..59ac9a36f6 100644 --- a/entc/gen/template/enttest.tmpl +++ b/entc/gen/template/enttest.tmpl @@ -102,7 +102,7 @@ func NewClient(t TestingT, opts ...Option) *{{ $pkg }}.Client { t.Error(err) t.FailNow() } - if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { + if err := migrate.Create(context.Background(), {{ if $.FeatureEnabled "sql/no-client-schema" }}migrate.NewSchema(c.Driver()){{ else }}c.Schema{{ end }}, tables, o.migrateOpts...); err != nil { t.Error(err) t.FailNow() }