diff --git a/content/english/blog/golang/app-architecture.md b/content/english/blog/golang/app-architecture.md new file mode 100644 index 0000000..350a218 --- /dev/null +++ b/content/english/blog/golang/app-architecture.md @@ -0,0 +1,204 @@ +--- +title: "One way to architecture your app" +meta_title: "" +description: "One way to architecture your app" +date: 2023-09-30T05:00:00Z +categories: ["golang", "architecture"] +author: "Hugo Sjoberg" +tags: ["golang", "architecture"] +draft: false +--- + +# One way to architecture your app + +One common question/talking point in the golang community is how to architect your application. It's a pretty loaded question and a lot of people have a strong opinion on what's the "right" way. I don't think that there is one way of architecture your app, that being said I will present one way of architecture your app. + +There are many architectures out there such as + - *Hexagonol Architecture* + - *Domain Driven Design* + - *CQRS* + - And many more + + Typically these design patterns do not have its roots in golang but rather stem from more traditional programming languages such as Java and C# where inheritance polymorphism and other OOP patterns is a big thing. While this kind of architecture might make sense in another programming language I don't necessarily think it makes sense in Golang. + + # Project Structure + +Let's start with the basic project structure, I typically try to follow this [resource](https://github.com/golang-standards/project-layout) as it's pretty commonly used throughout the industry. Also, the go team just wrote a [blog-post](https://go.dev/doc/modules/layout) about it. + +According to [Golang-standards Project layout](https://github.com/golang-standards/project-layout) we'll need the following: + +`/cmd` + +This will serve as the entry point to our program eg. `go run /cmd/api/my-app.go`, the code here should be super light, just invoke code from `/internal` and `/pkg` nothing else. + +`/internal` + +Private app and library code, this code is only to be consumed by this application/library. This is typically where most of your app code will end up. + +`/pkg` + +Code that is exported, other applications/libraries may import from here, for example, if we have an auth-middleware that can be shared with multiple projects. + +`/api` + +Here is where OpenAPI/Swagger files should be placed. + +`Makefile` + +Makefile to handle the commands needed to operate the project, e.g.: `make lint` for linting the code, `make generate` to run code-generators. + +# Generate your APIs + +As a programmer I'm lazy and as I'm getting older I also want consistency. For example, it's annoying when your OpenAPI/swagger differs from the actual implementation, so let's generate our APIs from our OpenAPI specification. + +To do this we can use a package such as [OAPI-codegen](https://github.com/deepmap/oapi-codegen) or the more flexible [goapi-gen](https://github.com/discord-gophers/goapi-gen). I prefer the latter since it allows to use middleware per endpoint instead of only adding middleware on the project level. + +Below is an example spec for two APIs, one user endpoint to fetch the current user and one admin endpoint to create a new user. + + +```yaml +openapi: 3.0.3 +servers: + - url: 'http://localhost/v1' +components: + schemas: + Error: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + User: + type: object + properties: + id: + type: string + name: + type: string +paths: + /user: + get: + description: Get's the current user + responses: + 200: + description: user response + content: + application/json: + schema: + $ref: '#/components/schemas/User' + default: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/user: + post: + description: Creates a user + responses: + 200: + description: Creates a user + content: + application/json: + schema: + $ref: '#/components/schemas/User' + default: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string +``` + +And a file to generate the handlers: + +```go +/internal/api/main.go +//go:generate go run github.com/discord-gophers/goapi-gen@v0.3.0 -o gen.go -package api ../../api/api.yaml +package api +``` + +Running `go generate ./...` will generate the interfaces for your handlers, pretty neat right? Now we just need to implement the interfaces. + +# Implement the interface + +We can create two new packages, `user` and `admin`, and you guessed it, all code needed for the user is in the user package and all the code needed for the admin is in the `admin` package. When I say all code needed for the user it would be all the handlers(API), all the business logic, database interactions etc. To keep things short I will just implement a super simple handlers. + +```golang +// internal/user/handler.go + +type UserHandler struct{} + +func (u *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) *api.Response { + id := "123" + name := "John Doe" + return api.GetUserJSON200Response(api.User{ID: &id, Name: &name}) +} + +func NewUserHandler() *UserHandler { + return &UserHandler{} +} +``` + +```golang +// internal/admin/handler.go + +type AdmimHandler struct{} + +func (u *AdmimHandler) PostAdminUser(w http.ResponseWriter, r *http.Request) *api.Response { + var req api.PostAdminUserJSONRequestBody + if err := render.Bind(r, &req); err != nil { + errorCode := int32(http.StatusBadRequest) + errorMessage := "Bad request" + return api.PostAdminUserJSONDefaultResponse(api.Error{Code: &errorCode, Message: &errorMessage}) + } + id := "123" + return api.PostAdminUserJSON200Response(api.User{ID: &id, Name: req.Name}) +} + +func NewAdmimHandler() *AdmimHandler { + return &AdmimHandler{} +} +``` + +And we can merge the Handlers together so that we implement the interface which we generated. + +```golang +// server/server.go + +type handlers struct { + user.UserHandler + admin.AdmimHandler +} + +func newHandler() *handlers { + return &handlers{ + UserHandler: *user.NewUserHandler(), + AdmimHandler: *admin.NewAdmimHandler(), + } +} + +func Start() { + apiHandler := api.Handler(newHandler()) + http.ListenAndServe(":8080", apiHandler) +} +``` + +Everything should run now :crossed_fingers: + +# Conclusion + +This architecture is not the most advanced architecture, as you can see there's not much abstraction and nothing magical(Ok, the code generation is pretty magical). I also don't think an architecture should be much more advanced than this, code is meant to be easy to read and easy to understand. The more abstractions or \ design-pattern we use the harder it get's to read, write and refactor code. + +The code used in this blog post can be found [here](https://github.com/hugosjoberg/blog-code/tree/main/architecture) diff --git a/content/english/blog/golang/singleflight.md b/content/english/blog/golang/singleflight.md index 3e745b0..a1300b0 100644 --- a/content/english/blog/golang/singleflight.md +++ b/content/english/blog/golang/singleflight.md @@ -2,7 +2,7 @@ title: "Singleflight" meta_title: "" description: "Singleflight in Golang" -date: 2022-04-04T05:00:00Z +date: 2023-09-20T05:00:00Z image: "/images/singleflight.png" categories: ["golang", "concurrency"] author: "Hugo Sjoberg" diff --git a/hugo_stats.json b/hugo_stats.json index 04da8a1..0ff7e29 100644 --- a/hugo_stats.json +++ b/hugo_stats.json @@ -3,7 +3,6 @@ "tags": [ "a", "article", - "base", "blockquote", "body", "button", @@ -28,6 +27,7 @@ "iframe", "img", "input", + "insert-buzzword", "kbd", "label", "li", @@ -317,6 +317,7 @@ "emphasis", "gallery", "gathering-of-personal-information", + "generate-your-apis", "graceful-shutdown", "heading-1", "heading-2", @@ -327,6 +328,7 @@ "hide-button", "i-wanna-talk-about-the-assassination-attempt", "image", + "implement-the-interface", "learning-and-growth", "link", "message", @@ -334,9 +336,11 @@ "nav-menu", "nav-toggle", "notice", + "one-way-to-architecture-your-app", "ordered-list", "paragraph", "privacy-policy-changes", + "project-structure", "protection-of-personal--information", "responsibility-of-contributors", "search-modal-input", diff --git a/resources/_gen/assets/css/css/style.css_82b067fd6c564693170dff5ae4660239.content b/resources/_gen/assets/css/css/style.css_82b067fd6c564693170dff5ae4660239.content index 8a945ed..2d0a64c 100644 --- a/resources/_gen/assets/css/css/style.css_82b067fd6c564693170dff5ae4660239.content +++ b/resources/_gen/assets/css/css/style.css_82b067fd6c564693170dff5ae4660239.content @@ -10747,6 +10747,15 @@ main { .content :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { margin-bottom: 0; } +.content :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::darkMode { + color: #64748b; + background-color: #f5f5f4; + border-radius: 0.25rem; + padding-left: 0.375rem; + padding-right: 0.375rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} .content { max-width: none; } diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_lanczos_smart1_3.png b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_lanczos_smart1_3.png new file mode 100644 index 0000000..d74b696 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_lanczos_smart1_3.png differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_q90_h2_lanczos_smart1_3.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_q90_h2_lanczos_smart1_3.webp new file mode 100644 index 0000000..b2baa97 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_fill_q90_h2_lanczos_smart1_3.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_lanczos_3.png b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_lanczos_3.png new file mode 100644 index 0000000..2031f06 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_lanczos_3.png differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..375fe8c Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_100x100_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_15865a14ef45e60b6e319acefe84e99f.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_15865a14ef45e60b6e319acefe84e99f.webp new file mode 100644 index 0000000..daa1c71 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_15865a14ef45e60b6e319acefe84e99f.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_1755bc348e6df8f02514733e8e1717df.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_1755bc348e6df8f02514733e8e1717df.webp new file mode 100644 index 0000000..0dbc84a Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_1755bc348e6df8f02514733e8e1717df.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_392x396_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_392x396_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..98a87af Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_392x396_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_lanczos_3.png b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_lanczos_3.png new file mode 100644 index 0000000..138ca7b Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_lanczos_3.png differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..1ca808b Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_420x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_6190c79289e513fd46c365bb53089d0d.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_6190c79289e513fd46c365bb53089d0d.webp new file mode 100644 index 0000000..6066dc9 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_6190c79289e513fd46c365bb53089d0d.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_8c293bda73ea676f6c91ab6c357f758e.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_8c293bda73ea676f6c91ab6c357f758e.webp new file mode 100644 index 0000000..baf2def Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_8c293bda73ea676f6c91ab6c357f758e.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_9e121f0f59040f8e31dcbb49e5143113.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_9e121f0f59040f8e31dcbb49e5143113.webp new file mode 100644 index 0000000..8a08379 Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_9e121f0f59040f8e31dcbb49e5143113.webp differ diff --git a/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_d8ddd1e1f5936cdde4393f3729917ec5.webp b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_d8ddd1e1f5936cdde4393f3729917ec5.webp new file mode 100644 index 0000000..84fc80c Binary files /dev/null and b/resources/_gen/images/architecture_hu35183a6fcd37bb344d017a9d32f2b72d_24847_d8ddd1e1f5936cdde4393f3729917ec5.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_0e5e64bfaca0ee7f71aa750bc321974c.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_0e5e64bfaca0ee7f71aa750bc321974c.png new file mode 100644 index 0000000..485f96f Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_0e5e64bfaca0ee7f71aa750bc321974c.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_lanczos_smart1_3.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_lanczos_smart1_3.png new file mode 100644 index 0000000..65750ce Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_lanczos_smart1_3.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_q90_h2_lanczos_smart1_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_q90_h2_lanczos_smart1_3.webp new file mode 100644 index 0000000..c2d1e3e Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_fill_q90_h2_lanczos_smart1_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_lanczos_3.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_lanczos_3.png new file mode 100644 index 0000000..eb51d29 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_lanczos_3.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..cc678c2 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_100x100_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_lanczos_3.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_lanczos_3.png new file mode 100644 index 0000000..1593c5b Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_lanczos_3.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..c0f649b Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_1110x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_253f3b7758d1f80473031c00d81a4804.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_253f3b7758d1f80473031c00d81a4804.webp new file mode 100644 index 0000000..45e06ea Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_253f3b7758d1f80473031c00d81a4804.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_lanczos_3.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_lanczos_3.png new file mode 100644 index 0000000..0e2aa8c Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_lanczos_3.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..de83e6b Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_420x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_538f05f481ed2f7f0ca0cad673c05641.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_538f05f481ed2f7f0ca0cad673c05641.webp new file mode 100644 index 0000000..1547b51 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_538f05f481ed2f7f0ca0cad673c05641.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_545x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_545x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..8480186 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_545x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_5b761c395becb7984427887c0a3acfbf.png b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_5b761c395becb7984427887c0a3acfbf.png new file mode 100644 index 0000000..33dfb4f Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_5b761c395becb7984427887c0a3acfbf.png differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_600x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_600x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..76aa640 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_600x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_700x0_resize_q90_h2_lanczos_3.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_700x0_resize_q90_h2_lanczos_3.webp new file mode 100644 index 0000000..98ce696 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_700x0_resize_q90_h2_lanczos_3.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_b3e42dce94cfff12a2b6fe06d2b94f57.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_b3e42dce94cfff12a2b6fe06d2b94f57.webp new file mode 100644 index 0000000..19a3747 Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_b3e42dce94cfff12a2b6fe06d2b94f57.webp differ diff --git a/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_edce0667f5c0784dda4a1c6fa2bf50e2.webp b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_edce0667f5c0784dda4a1c6fa2bf50e2.webp new file mode 100644 index 0000000..d49085a Binary files /dev/null and b/resources/_gen/images/architecture_hu7ec2724c24e23968092d40b048b31443_69744_edce0667f5c0784dda4a1c6fa2bf50e2.webp differ diff --git a/tailwind.config.js b/tailwind.config.js index 4ebd12a..696a61d 100755 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -85,6 +85,15 @@ module.exports = { paddingTop: theme('spacing.1'), paddingBottom: theme('spacing.1'), }, + 'code::darkMode': { + color: theme('colors.slate.500'), + backgroundColor: theme('colors.stone.100'), + borderRadius: theme('borderRadius.DEFAULT'), + paddingLeft: theme('spacing[1.5]'), + paddingRight: theme('spacing[1.5]'), + paddingTop: theme('spacing.1'), + paddingBottom: theme('spacing.1'), + }, } } }