-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
// Copyright 2026 Shota FUJI
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/evanw/esbuild/pkg/api"
)
func main() {
outfile := flag.String("outfile", "", "Path to the output file")
depfile := flag.String("depfile", "", "Path to the depfile")
entrypoint := flag.String("entrypoint", "", "Path to the input file")
flag.Parse()
if *outfile == "" {
fmt.Fprintln(os.Stderr, "outfile must be set")
os.Exit(1)
}
if *entrypoint == "" {
fmt.Fprintln(os.Stderr, "entrypoint must be set")
os.Exit(1)
}
infiles := make([]string, 0, 64)
recordInfilePlugin := api.Plugin{
Name: "record_infile",
Setup: func(build api.PluginBuild) {
build.OnLoad(api.OnLoadOptions{Filter: ".*"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) {
infiles = append(infiles, args.Path)
return api.OnLoadResult{}, nil
})
},
}
saneCssPlugin := api.Plugin{
Name: "css_string",
Setup: func(build api.PluginBuild) {
build.OnLoad(api.OnLoadOptions{Filter: "\\.css$"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) {
text, err := os.ReadFile(args.Path)
if err != nil {
return api.OnLoadResult{}, err
}
result := api.Transform(string(text), api.TransformOptions{
Loader: api.LoaderCSS,
MinifyWhitespace: true,
MinifyIdentifiers: true,
MinifySyntax: true,
})
if len(result.Errors) > 0 {
msg := api.FormatMessages(result.Errors, api.FormatMessagesOptions{
Kind: api.ErrorMessage,
Color: false,
})
fmt.Printf("%s\n", strings.Join(msg, "\n"))
return api.OnLoadResult{}, fmt.Errorf("CSS minification failed")
}
contents := string(result.Code)
return api.OnLoadResult{
Contents: &contents,
Loader: api.LoaderText,
}, nil
})
},
}
result := api.Build(api.BuildOptions{
EntryPoints: []string{*entrypoint},
Bundle: true,
Outfile: *outfile,
Write: true,
MinifyWhitespace: true,
MinifyIdentifiers: true,
MinifySyntax: true,
Plugins: []api.Plugin{recordInfilePlugin, saneCssPlugin},
})
if len(result.Errors) > 0 {
for _, err := range result.Errors {
fmt.Fprintln(os.Stderr, err.Text)
}
os.Exit(1)
}
if len(result.OutputFiles) == 0 {
fmt.Fprintln(os.Stderr, "No output files were generated")
os.Exit(1)
}
if len(result.OutputFiles) > 1 {
fmt.Fprintln(os.Stderr, "More than one file were generated")
os.Exit(1)
}
if *depfile != "" {
outfile := result.OutputFiles[0]
depfile, err := os.OpenFile(*depfile, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to generate depfile: %v\n", err)
os.Exit(2)
}
defer depfile.Close()
fmt.Fprintf(depfile, "%s:", outfile.Path)
for _, infile := range infiles {
fmt.Fprintf(depfile, " \\\n\t%s", infile)
}
fmt.Fprint(depfile, "\n")
}
os.Exit(0)
}