diff options
| author | Shulhan <ms@kilabit.info> | 2024-08-09 15:21:01 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-08-09 15:21:01 +0700 |
| commit | 473738cfc9b33c18ee749112c7d248f4f626e7fb (patch) | |
| tree | debb0c880a59dbbd915c8453b035051704be8fe8 | |
| parent | f703cf50a4e3b2092a5ad615eef9bd56f58a25d3 (diff) | |
| download | pakakeh.go-473738cfc9b33c18ee749112c7d248f4f626e7fb.tar.xz | |
lib/memfs: document the comparison with "go:embed" directive
Compared it with "go:embed", the memfs package is more flexible and
portable.
Currently, we found three disadvantages of using "go:embed",
#1 - The "go:embed" only works if files or directory to be
embedded is in the same parent directory.
#2 - Accessing the embedded file require the original path.
#3 - No development mode.
| -rw-r--r-- | lib/memfs/doc.go | 166 |
1 files changed, 138 insertions, 28 deletions
diff --git a/lib/memfs/doc.go b/lib/memfs/doc.go index bddb4831..fc892ff3 100644 --- a/lib/memfs/doc.go +++ b/lib/memfs/doc.go @@ -7,7 +7,7 @@ // // # Usage // -// The first step is to create new instance of memfs using `New()`. +// The first step is to create new instance of memfs using [New] function. // The following example embed all files inside directory named "include" or // any files with extension ".css", ".html", and ".js"; // but exclude any files inside directory named "exclude". @@ -26,15 +26,18 @@ // // By default only file with size less or equal to 5 MB will be included in // memory. -// To increase the default size set the MaxFileSize (in bytes). -// For example, to set maximum file size to 10 MB, +// To increase the default size set the [Options.MaxFileSize] (in bytes). +// For example, to change maximum file size to 10 MB, // -// opts.MaxFileSize = 1024 * 1024 * 10 +// var opts = memfs.Options{ +// MaxFileSize: 1024 * 1024 * 10, +// } // -// Later, if we want to get the file from memory, call Get() which will return -// the node object with content can be accessed from field "Content". -// Remember that if file size is larger that maximum, -// the content will need to be read manually, +// Later, if we want to get the file from memory, call [MemFS.Get] which +// will return the [Node] object with content can be accessed from field +// "Content". +// If file size is larger than maximum, the content will need to be read +// manually (as long as the file exist on system), // // node, err := mfs.Get("/") // if err != nil { @@ -51,23 +54,27 @@ // // # Go embed // -// The memfs package also support embedding the files into Go generated source -// file. -// After we create memfs instance, we call GoEmbed() to dump all directory -// and files as Go source code. +// The memfs package support embedding the files into Go generated source +// code. +// After we create the MemFS instance, call the [GoEmbed] method to dump all +// directory and files into Go source code. // -// First, define global variable as container for all files later in the same -// package as generated code, +// First, define global variable as container for all files to be embedded +// in the same package as generated code, // // package mypackage // // var myFS *memfs.MemFS // -// Second, create new instance of MemFS with Options.Embed is set, and write -// the content of memfs instance as Go source code file, +// Second, create new instance of MemFS with [Options.Embed] is set, // -// opts := &Options{ -// Root: "./mydir", +// var opts = &Options{ +// Embed: EmbedOptions{ +// PackageName: `mypackage`, +// VarName: `myFS`, +// GoFileName: `mypackage/embed.go`, +// }, +// Root: `./mydir`, // Includes: []string{ // `.*/include`, // `.*\.(css|html|js)$`, @@ -75,18 +82,121 @@ // Excludes: []string{ // `.*/exclude`, // }, -// Embed: EmbedOptions{ -// PackageName: "mypackage", -// VarName: "myFS", -// GoFileName: "mypackage/embed.go", -// }, // } -// mfs, _ := memfs.New(opts) +// +// var mfs *memfs.MemFS +// mfs, err = memfs.New(opts) +// ... +// +// Third, call method [MemFS.GoEmbed] from the instance, +// // mfs.GoEmbed() // -// The Go generated file will be defined with package named "mypackage" using -// global variable "myFS" as container stored in file "mypackage/file.go" -// with each content encoded (compressed) using gzip. +// This method will create Go file "mypackage/embed.go" that contains all +// path and content of files inside the mfs instance, under package named +// "mypackage". +// Code that can read "myFS" variable then can access any files using +// [MemFS.Get] method, with "/" as root prefix (not "./mydir"). +// +// # Comparison with builtin go:embed +// +// This section list the disadvantages of "go:embed" directive. +// +// The memfs package created on [November 2018], based on my experiences +// maintains the fork of [go-bindata] project. +// The "go:embed" directive introduced into Go tools since +// [Go version 1.16], released February 2021, three years after the first +// release of memfs package. +// +// Given the following directory structure, +// +// module-root/ +// +-- cmd/prog/main.go +// +-- _content/ +// +-- index.adoc +// +-- index.html +// +-- static/ +// +-- index.png +// +-- index.png +// +// We want to embed the directory "_content" but only html files and all +// files inside the "static/" directory. +// +// Cons #1: The "go:embed" only works if files or directory to be embedded +// is in the same parent directory. +// +// The "go:embed" directive define in "cmd/prog/main.go" will not +// able to embed files in their parent. +// The following code will not compile, +// +// //go:embed ../../_content/*.html +// //go:embed ../../_content/static +// var contentFS embed.FS +// +// // go build output, +// // pattern ../../_content/*.html: invalid pattern syntax +// +// If we remove the ".." and execute "go build" from module-root, it will +// still not compile, +// +// //go:embed _content/*.html +// //go:embed _content/static +// var contentFS embed.FS +// +// // go build or run output, +// // pattern _content/*.html: no matching files found +// +// The only solution is to create and export the variable "ContentFS" in the +// same parent directory as "_content". +// +// The memfs package does not have this limitation. +// As long as the Go commands are executed from the module-root directory, +// you can define the variable in any packages. +// +// Cons #2: Accessing the embedded file require the original path. +// +// Let say we have embeded the "_content" directory using the following +// syntax, +// +// //go:embed _content/*.html +// //go:embed _content/static +// var ContentFS embed.FS +// +// To access the file "index.html" you need to pass their full path, in this +// case "_content/index.html". +// The path "_content" leaked to the parent FS and not portable. +// +// In the memfs package, the content of [Options.Root] directory can be +// accessed with "/", so it would become "/index.html". +// This design allow flexibility and consistency between modules and +// packages. +// If an external, third-party package accept the MemFS instance and the +// first thing they do is to read all contents of "/" directory, the caller +// can embed any path without have specific prefix or name. +// +// Case example, when we embed SQL files for migration under directory +// "db/migration" using the "go:embed" directive, +// +// //go:embed db/migration/*.sql +// var DBMigrationFS embed.FS +// +// and then call the [Migrate] function, it cannot found any ".sql" files +// inside the "/" directory because the files is stored under +// "db/migration/" prefix. +// +// Cons #3: No development mode. +// +// Let say we run our server that served the content from FS instance. +// If we changes the html files, and refresh the browser, the new content +// will not reflected because it serve the content on the first embed. +// +// The memfs package have [Options.TryDirect] that bypass file in memory and +// read directly to the file system. +// This allow quick development when changes only template or non-code +// files. // -// Thats it! +// [November 2018]: https://git.sr.ht/~shulhan/pakakeh.go/commit/05b02c7b +// [go-bindata]: https://github.com/shuLhan/go-bindata +// [Go version 1.16]: https://go.dev/doc/go1.16 +// [Migrate]: https://pkg.go.dev/git.sr.ht/~shulhan/pakakeh.go/lib/sql#Client.Migrate package memfs |
