bundler
API
bundler
packageAPI reference for the bundler
package.
Imports
(12)
STD
encoding/json
STD
os
STD
path/filepath
STD
strings
INT
github.com/rfwlab/rfw/cmd/rfw/logging
INT
github.com/rfwlab/rfw/cmd/rfw/plugins
INT
github.com/rfwlab/rfw/cmd/rfw/utils
PKG
github.com/tdewolff/minify/v2
PKG
github.com/tdewolff/minify/v2/css
PKG
github.com/tdewolff/minify/v2/html
PKG
github.com/tdewolff/minify/v2/js
STD
testing
S
struct
plugin
cmd/rfw/plugins/bundler/bundler.go:18-18
type plugin struct
Methods
PostBuild
Method
Parameters
raw
json.RawMessage
Returns
error
func (*plugin) PostBuild(raw json.RawMessage) error
{
if utils.IsDebug() {
logging.Log.Info("skipped in debug mode", logging.F("plugin", "bundler"))
return nil
}
m := minify.New()
m.AddFunc("text/javascript", js.Minify)
m.AddFunc("text/css", css.Minify)
m.AddFunc("text/html", html.Minify)
buildDir := "build"
if err := filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
ext := filepath.Ext(path)
var media string
switch ext {
case ".js":
media = "text/javascript"
case ".css":
if isTailwindCSS(path) {
logging.Log.Info("skipping tailwind css", logging.F("plugin", "bundler"), logging.F("path", path))
return nil
}
media = "text/css"
case ".html":
media = "text/html"
default:
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return err
}
out, err := m.Bytes(media, data)
if err != nil {
return err
}
if err := os.WriteFile(path, out, 0o644); err != nil {
return err
}
return nil
}); err != nil {
return err
}
logging.Log.Info("build complete", logging.F("plugin", "bundler"))
return nil
}
ShouldRebuild
Method
Parameters
path
string
Returns
bool
func (*plugin) ShouldRebuild(path string) bool
{
path = filepath.ToSlash(path)
if strings.HasPrefix(path, "build/") {
return false
}
return strings.HasSuffix(path, ".js") || strings.HasSuffix(path, ".css") || strings.HasSuffix(path, ".html")
}
F
function
init
cmd/rfw/plugins/bundler/bundler.go:20-20
func init()
{ plugins.Register(&plugin{}) }
F
function
isTailwindCSS
Parameters
path
string
Returns
bool
cmd/rfw/plugins/bundler/bundler.go:88-95
func isTailwindCSS(path string) bool
{
data, err := os.ReadFile(path)
if err != nil {
return false
}
src := string(data)
return strings.Contains(src, "@tailwind") || strings.Contains(src, "tailwindcss")
}
F
function
TestShouldRebuild
Parameters
t
cmd/rfw/plugins/bundler/bundler_test.go:11-28
func TestShouldRebuild(t *testing.T)
{
p := &plugin{}
if !p.ShouldRebuild("main.js") {
t.Fatalf("expected js change to trigger rebuild")
}
if !p.ShouldRebuild("styles.css") {
t.Fatalf("expected css change to trigger rebuild")
}
if !p.ShouldRebuild("index.html") {
t.Fatalf("expected html change to trigger rebuild")
}
if p.ShouldRebuild(filepath.Join("build", "app.js")) {
t.Fatalf("output directory should not trigger rebuild")
}
if p.ShouldRebuild("image.png") {
t.Fatalf("unrelated files should not trigger rebuild")
}
}
F
function
TestIsTailwindCSS
Parameters
t
cmd/rfw/plugins/bundler/bundler_test.go:30-47
func TestIsTailwindCSS(t *testing.T)
{
dir := t.TempDir()
tw := filepath.Join(dir, "input.css")
if err := os.WriteFile(tw, []byte("@import \"tailwindcss\";"), 0o644); err != nil {
t.Fatalf("write tailwind file: %v", err)
}
if !isTailwindCSS(tw) {
t.Fatalf("expected tailwind directives to be detected")
}
normal := filepath.Join(dir, "normal.css")
if err := os.WriteFile(normal, []byte("body{}"), 0o644); err != nil {
t.Fatalf("write normal file: %v", err)
}
if isTailwindCSS(normal) {
t.Fatalf("unexpected tailwind detection in normal css")
}
}
F
function
TestPostBuildMinifiesFiles
Parameters
t
cmd/rfw/plugins/bundler/bundler_test.go:49-95
func TestPostBuildMinifiesFiles(t *testing.T)
{
dir := t.TempDir()
buildDir := filepath.Join(dir, "build", "static")
if err := os.MkdirAll(buildDir, 0o755); err != nil {
t.Fatalf("mkdir build: %v", err)
}
jsFile := filepath.Join(buildDir, "app.js")
if err := os.WriteFile(jsFile, []byte("function add ( a , b ){ return a + b ; }"), 0o644); err != nil {
t.Fatalf("write js: %v", err)
}
cssFile := filepath.Join(buildDir, "app.css")
if err := os.WriteFile(cssFile, []byte("body { color: red; }"), 0o644); err != nil {
t.Fatalf("write css: %v", err)
}
htmlFile := filepath.Join(buildDir, "index.html")
html := "<html><head><title> hi </title></head><body> <h1> hi </h1> </body></html>"
if err := os.WriteFile(htmlFile, []byte(html), 0o644); err != nil {
t.Fatalf("write html: %v", err)
}
wd, _ := os.Getwd()
defer os.Chdir(wd)
if err := os.Chdir(dir); err != nil {
t.Fatalf("chdir: %v", err)
}
utils.EnableDebug(false)
p := &plugin{}
if err := p.PostBuild(nil); err != nil {
t.Fatalf("postbuild: %v", err)
}
outJS, _ := os.ReadFile(jsFile)
if len(outJS) >= len("function add ( a , b ){ return a + b ; }") {
t.Fatalf("js not minified: %s", outJS)
}
outCSS, _ := os.ReadFile(cssFile)
if len(outCSS) >= len("body { color: red; }") {
t.Fatalf("css not minified: %s", outCSS)
}
outHTML, _ := os.ReadFile(htmlFile)
if len(outHTML) >= len(html) {
t.Fatalf("html not minified: %s", outHTML)
}
}
F
function
TestPostBuildSkippedInDebug
Parameters
t
cmd/rfw/plugins/bundler/bundler_test.go:97-128
func TestPostBuildSkippedInDebug(t *testing.T)
{
dir := t.TempDir()
buildDir := filepath.Join(dir, "build", "static")
if err := os.MkdirAll(buildDir, 0o755); err != nil {
t.Fatalf("mkdir build: %v", err)
}
jsFile := filepath.Join(buildDir, "app.js")
content := "function add ( a , b ){ return a + b ; }"
if err := os.WriteFile(jsFile, []byte(content), 0o644); err != nil {
t.Fatalf("write js: %v", err)
}
wd, _ := os.Getwd()
defer os.Chdir(wd)
if err := os.Chdir(dir); err != nil {
t.Fatalf("chdir: %v", err)
}
utils.EnableDebug(true)
defer utils.EnableDebug(false)
p := &plugin{}
if err := p.PostBuild(nil); err != nil {
t.Fatalf("postbuild: %v", err)
}
out, _ := os.ReadFile(jsFile)
if string(out) != content {
t.Fatalf("file should remain unminified, got %s", out)
}
}