…lines 1–42 unchanged (42 lines)
43
44const (
45 PrefixHugoVirtual = "__hu_v"
46 PrefixHugoMemory = "__hu_m"
47)
48
49var extensionToLoaderMapJS = map[string]api.Loader{
50 ".js": api.LoaderJS,
51 ".mjs": api.LoaderJS,
52 ".cjs": api.LoaderJS,
53 ".jsx": api.LoaderJSX,
54 ".ts": api.LoaderTS,
55 ".tsx": api.LoaderTSX,
56 ".json": api.LoaderJSON,
57 ".txt": api.LoaderText,
58 ".css": api.LoaderCSS,
59}
60
61var extensionToLoaderMapCSS = map[string]api.Loader{
62 ".css": api.LoaderCSS,
63}
64
65// This is a common sub-set of ESBuild's default extensions.
66// We assume that imports of JSON, CSS etc. will be using their full
67// name with extension.
68var commonExtensions = []string{".js", ".ts", ".tsx", ".jsx"}
69
…lines 70–141 unchanged (72 lines)
142
143type fsResolver struct {
144 fs afero.Fs
145 resolved *hmaps.Cache[string, *hugofs.FileMeta]
146}
147
148func (r *fsResolver) resolveComponent(impPath string, direct bool) *hugofs.FileMeta {
149 v, _ := r.resolved.GetOrCreate(impPath, func() (*hugofs.FileMeta, error) {
150 resolve := func(name string) (*hugofs.FileMeta, bool, bool) {
151 if fi, err := r.fs.Stat(name); err == nil {
152 return fi.(hugofs.FileMetaInfo).Meta(), true, fi.IsDir()
153 }
154 return nil, false, false
155 }
156 if direct {
157 // Only resolve the path as is, without trying to add extensions etc.
158 v, found, isDir := resolve(impPath)
159 if found && !isDir {
160 return v, nil
161 }
162 return nil, nil
163 }
164 v, _ := ResolveComponent(impPath, resolve)
165 return v, nil
166 })
167 return v
168}
169
170func createBuildPlugins(rs *resources.Spec, assetsResolver *fsResolver, depsManager identity.Manager, opts Options) ([]api.Plugin, error) {
171 fs := rs.Assets
172
173 resolveImport := func(args api.OnResolveArgs) (api.OnResolveResult, error) {
174 impPath := args.Path
175 isCSSToken := args.Kind == api.ResolveCSSImportRule || args.Kind == api.ResolveCSSURLToken
176
177 shimmed := false
178 if opts.Shims != nil {
179 override, found := opts.Shims[impPath]
180 if found {
181 impPath = override
…lines 182–218 unchanged (37 lines)
219 relDir = filepath.Dir(rel)
220 }
221 }
222 } else {
223 relDir = opts.SourceDir
224 }
225
226 var pathsToTry []string
227
228 if relDir != "" {
229 // For JS imports not starting with a "." is assumed to live relative to /assets.
230 // Hugo makes no assumptions about the directory structure below /assets.
231 if strings.HasPrefix(impPath, ".") {
232 pathsToTry = append(pathsToTry, filepath.Join(relDir, impPath))
233 } else if isCSSToken && !strings.HasPrefix(impPath, "/") {
234 // Follow the logic of both ESBuild and WebKit for CSS @import and url() tokens.
235 // First try the relativ path, then the assets relative path.
236 // See https://github.com/evanw/esbuild/issues/469
237 pathsToTry = append(pathsToTry, filepath.Join(relDir, impPath), impPath)
238 } else {
239 // Try only the assets relative path.
240 pathsToTry = append(pathsToTry, impPath)
241 }
242 }
243
244 var m *hugofs.FileMeta
245 for _, p := range pathsToTry {
246 m = assetsResolver.resolveComponent(p, isCSSToken)
247 if m != nil {
248 break
249 }
250 }
251
252 if m != nil {
253 depsManager.AddIdentity(m.PathInfo)
254
255 // jsconfig.json path mapping has no effect for CSS imports, so skip those.
256 if !isCSSToken {
257 // Store the source root so we can create a jsconfig.json
258 // to help IntelliSense when the build is done.
259 // This should be a small number of elements, and when
260 // in server mode, we may get stale entries on renames etc.,
261 // but that shouldn't matter too much.
262 rs.JSConfigBuilder.AddSourceRoot(m.SourceRoot)
263 }
264
265 return api.OnResolveResult{Path: m.Filename, Namespace: NsHugoImport}, nil
266 }
267
268 // Fall back to ESBuild's resolve.
269 return api.OnResolveResult{}, nil
…lines 270–361 unchanged (92 lines)