mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 07:18:54 +00:00
resources: Support babel/postcss config variants
Allow modules to use .mjs and .cjs file extensions for Babel and PostCSS configuration files instead of just .js. Closes #15039 Closes #15040 Closes #15043
This commit is contained in:
committed by
Bjørn Erik Pedersen
parent
f013346667
commit
9d66d513ce
@@ -88,7 +88,7 @@ var defaultBuild = BuildConfig{
|
||||
|
||||
CacheBusters: []CacheBuster{
|
||||
{
|
||||
Source: `(postcss|tailwind)\.config\.js`,
|
||||
Source: `(postcss|tailwind)\.config\.(js|mjs|cjs)`,
|
||||
Target: cssTargetCachebusterRe,
|
||||
},
|
||||
},
|
||||
|
||||
+19
-6
@@ -1165,7 +1165,7 @@ config:
|
||||
disableTags: false
|
||||
enable: false
|
||||
cacheBusters:
|
||||
- source: '(postcss|tailwind)\.config\.js'
|
||||
- source: '(postcss|tailwind)\.config\.(js|mjs|cjs)'
|
||||
target: (css|styles|scss|sass)
|
||||
noJSConfigInAssets: false
|
||||
useResourceCacheWhen: fallback
|
||||
@@ -1272,24 +1272,31 @@ config:
|
||||
ignoreVendorPaths: ''
|
||||
imaging:
|
||||
anchor: smart
|
||||
avif:
|
||||
compression: lossy
|
||||
encoderSpeed: 10
|
||||
hint: photo
|
||||
quality: 60
|
||||
bgColor: ffffff
|
||||
compression: lossy
|
||||
exif:
|
||||
disableDate: false
|
||||
disableLatLong: false
|
||||
excludeFields: GPS|Exif|Exposure[M|P|B]|Contrast|Resolution|Sharp|JPEG|Metering|Sensing|Saturation|ColorSpace|Flash|WhiteBalance
|
||||
includeFields: ''
|
||||
jpeg:
|
||||
quality: 75
|
||||
meta:
|
||||
fields:
|
||||
- '! *{GPS,Exif,Exposure[MPB],Contrast,Resolution,Sharp,JPEG,Metering,Sensing,Saturation,ColorSpace,Flash,WhiteBalance}*'
|
||||
sources:
|
||||
- exif
|
||||
- iptc
|
||||
quality: 75
|
||||
resampleFilter: box
|
||||
webp:
|
||||
compression: lossy
|
||||
hint: photo
|
||||
method: 2
|
||||
quality: 75
|
||||
useSharpYuv: false
|
||||
languages:
|
||||
en:
|
||||
@@ -2043,6 +2050,8 @@ config:
|
||||
weight: 0
|
||||
sectionPagesMenu: ''
|
||||
security:
|
||||
allowContent:
|
||||
- '! ^text/html$'
|
||||
enableInlineShortcodes: false
|
||||
exec:
|
||||
allow:
|
||||
@@ -4612,11 +4621,15 @@ tpl:
|
||||
- highlight
|
||||
Args:
|
||||
- s
|
||||
- lang
|
||||
- opts
|
||||
- args
|
||||
Description: |-
|
||||
Highlight returns a copy of s as an HTML string with syntax
|
||||
Highlight returns a copy of CODE as an HTML string with syntax
|
||||
highlighting applied.
|
||||
|
||||
transform.Highlight CODE [LANG] [OPTIONS]
|
||||
|
||||
LANG is optional; it can also be set via the type option in OPTIONS, which
|
||||
makes this work the same way as HighlightCodeBlock.
|
||||
Examples: []
|
||||
HighlightCodeBlock:
|
||||
Aliases: null
|
||||
|
||||
+1
-1
@@ -656,7 +656,7 @@ func (c *collector) loadModules() error {
|
||||
}
|
||||
|
||||
// Matches postcss.config.js etc.
|
||||
var commonJSConfigs = regexp.MustCompile(`(babel|postcss|tailwind)\.config\.js`)
|
||||
var commonJSConfigs = regexp.MustCompile(`^(babel|postcss|tailwind)\.config\.(c|m)?js$`)
|
||||
|
||||
func (c *collector) mountCommonJSConfig(owner *moduleAdapter, mounts []Mount) ([]Mount, error) {
|
||||
for _, m := range mounts {
|
||||
|
||||
@@ -130,17 +130,23 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx
|
||||
if t.options.Config != "" {
|
||||
configFile = t.options.Config
|
||||
} else {
|
||||
configFile = "babel.config.js"
|
||||
for _, name := range []string{"babel.config.js", "babel.config.mjs", "babel.config.cjs"} {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(name)
|
||||
if configFile != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFile = filepath.Clean(configFile)
|
||||
|
||||
// We need an absolute filename to the config file.
|
||||
if !filepath.IsAbs(configFile) {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
|
||||
if configFile == "" && t.options.Config != "" {
|
||||
// Only fail if the user specified config file is not found.
|
||||
return fmt.Errorf("babel config %q not found", configFile)
|
||||
if configFile != "" {
|
||||
configFile = filepath.Clean(configFile)
|
||||
// We need an absolute filename to the config file.
|
||||
if !filepath.IsAbs(configFile) {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
|
||||
if configFile == "" && t.options.Config != "" {
|
||||
// Only fail if the user specified config file is not found.
|
||||
return fmt.Errorf("babel config %q not found", t.options.Config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
package babel_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/hugolib"
|
||||
)
|
||||
|
||||
@@ -83,3 +88,103 @@ Transpiled3: {{ $transpiled.Permalink }}
|
||||
b.AssertFileContent("public/index.html", `
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozL`)
|
||||
}
|
||||
|
||||
// See Issue 15043.
|
||||
// See Issue 15040.
|
||||
func TestTransformBabelConfigResolution(t *testing.T) {
|
||||
if !htesting.IsCI() {
|
||||
t.Skip("Skip long running test when running locally")
|
||||
}
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[[module.imports]]
|
||||
path = "github.com/bep/hugo-mod-nop"
|
||||
[security]
|
||||
[security.exec]
|
||||
allow = ['^go$', '^node$', '^babel$']
|
||||
-- assets/js/main.js --
|
||||
/* A Car */
|
||||
class Car {
|
||||
constructor(brand) {
|
||||
this.carname = brand;
|
||||
}
|
||||
}
|
||||
-- layouts/home.html --
|
||||
{{ $js := resources.Get "js/main.js" | babel }}
|
||||
RelPermalink: {{ $js.RelPermalink }}|HasBody: {{ gt (len $js.Content) 0 }}|
|
||||
-- package.json --
|
||||
{
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.28.6",
|
||||
"@babel/core": "7.28.6"
|
||||
}
|
||||
}
|
||||
-- go.mod --
|
||||
module github.com/example/project
|
||||
|
||||
go 1.26
|
||||
|
||||
replace github.com/bep/hugo-mod-nop => ../external-module
|
||||
-- ../external-module/go.mod --
|
||||
module github.com/bep/hugo-mod-nop
|
||||
|
||||
go 1.26
|
||||
-- ../external-module/CONFIG_FILE_NAME --
|
||||
CONFIG_FILE_CONTENT
|
||||
`
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
configFileName string
|
||||
configFileContent string
|
||||
}{
|
||||
{
|
||||
name: "mjs in module",
|
||||
configFileName: "babel.config.mjs",
|
||||
configFileContent: "export default {};\n",
|
||||
},
|
||||
{
|
||||
name: "cjs in module",
|
||||
configFileName: "babel.config.cjs",
|
||||
configFileContent: "module.exports = {};\n",
|
||||
},
|
||||
{
|
||||
name: "js in module",
|
||||
configFileName: "babel.config.js",
|
||||
configFileContent: "module.exports = {};\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
rootDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-integration-test")
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Cleanup(clean)
|
||||
|
||||
projectDir := filepath.Join(rootDir, "project")
|
||||
moduleDir := filepath.Join(rootDir, "external-module")
|
||||
c.Assert(os.MkdirAll(projectDir, 0o755), qt.IsNil)
|
||||
c.Assert(os.MkdirAll(moduleDir, 0o755), qt.IsNil)
|
||||
|
||||
f := strings.ReplaceAll(files, "CONFIG_FILE_NAME", tt.configFileName)
|
||||
f = strings.ReplaceAll(f, "CONFIG_FILE_CONTENT", tt.configFileContent)
|
||||
|
||||
b := hugolib.Test(c, f,
|
||||
hugolib.TestOptWithConfig(func(cfg *hugolib.IntegrationTestConfig) {
|
||||
cfg.WorkingDir = projectDir
|
||||
cfg.NeedsOsFS = true
|
||||
cfg.NeedsNpmInstall = true
|
||||
}),
|
||||
hugolib.TestOptInfo(),
|
||||
)
|
||||
|
||||
b.AssertFileContent("public/index.html",
|
||||
"RelPermalink: /js/main.js|HasBody: true|",
|
||||
)
|
||||
b.AssertLogContains(tt.configFileName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,17 +157,23 @@ func (t *postcssTransformation) Transform(ctx *resources.ResourceTransformationC
|
||||
if options.Config != "" {
|
||||
configFile = options.Config
|
||||
} else {
|
||||
configFile = "postcss.config.js"
|
||||
for _, name := range []string{"postcss.config.js", "postcss.config.mjs", "postcss.config.cjs"} {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(name)
|
||||
if configFile != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFile = filepath.Clean(configFile)
|
||||
|
||||
// We need an absolute filename to the config file.
|
||||
if !filepath.IsAbs(configFile) {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
|
||||
if configFile == "" && options.Config != "" {
|
||||
// Only fail if the user specified config file is not found.
|
||||
return fmt.Errorf("postcss config %q not found", options.Config)
|
||||
if configFile != "" {
|
||||
configFile = filepath.Clean(configFile)
|
||||
// We need an absolute filename to the config file.
|
||||
if !filepath.IsAbs(configFile) {
|
||||
configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
|
||||
if configFile == "" && options.Config != "" {
|
||||
// Only fail if the user specified config file is not found.
|
||||
return fmt.Errorf("postcss config %q not found", options.Config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,6 +216,97 @@ Styles Content: Len: 770917
|
||||
}
|
||||
}
|
||||
|
||||
// See Issue 15039.
|
||||
// See Issue 15040.
|
||||
func TestTransformPostCSSConfigResolution(t *testing.T) {
|
||||
if !htesting.IsCI() {
|
||||
t.Skip("Skip long running test when running locally")
|
||||
}
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[[module.imports]]
|
||||
path = "github.com/bep/hugo-mod-nop"
|
||||
-- assets/css/styles.css --
|
||||
body { color: red }
|
||||
-- layouts/home.html --
|
||||
{{ $styles := resources.Get "css/styles.css" | css.PostCSS }}
|
||||
RelPermalink: {{ $styles.RelPermalink }}|HasBody: {{ in $styles.Content "color:" }}|
|
||||
-- package.json --
|
||||
{
|
||||
"devDependencies": {
|
||||
"postcss-cli": "11.0.0"
|
||||
}
|
||||
}
|
||||
-- go.mod --
|
||||
module github.com/example/project
|
||||
|
||||
go 1.26
|
||||
|
||||
replace github.com/bep/hugo-mod-nop => ../external-module
|
||||
-- ../external-module/go.mod --
|
||||
module github.com/bep/hugo-mod-nop
|
||||
|
||||
go 1.26
|
||||
-- ../external-module/CONFIG_FILE_NAME --
|
||||
CONFIG_FILE_CONTENT
|
||||
`
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
configFileName string
|
||||
configFileContent string
|
||||
}{
|
||||
{
|
||||
name: "mjs in module",
|
||||
configFileName: "postcss.config.mjs",
|
||||
configFileContent: "export default {};\n",
|
||||
},
|
||||
{
|
||||
name: "cjs in module",
|
||||
configFileName: "postcss.config.cjs",
|
||||
configFileContent: "module.exports = {};\n",
|
||||
},
|
||||
{
|
||||
name: "js in module",
|
||||
configFileName: "postcss.config.js",
|
||||
configFileContent: "module.exports = {};\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
rootDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-integration-test")
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Cleanup(clean)
|
||||
|
||||
projectDir := filepath.Join(rootDir, "project")
|
||||
moduleDir := filepath.Join(rootDir, "external-module")
|
||||
c.Assert(os.MkdirAll(projectDir, 0o755), qt.IsNil)
|
||||
c.Assert(os.MkdirAll(moduleDir, 0o755), qt.IsNil)
|
||||
|
||||
f := strings.ReplaceAll(files, "CONFIG_FILE_NAME", tt.configFileName)
|
||||
f = strings.ReplaceAll(f, "CONFIG_FILE_CONTENT", tt.configFileContent)
|
||||
|
||||
b := hugolib.Test(c, f,
|
||||
hugolib.TestOptWithConfig(func(cfg *hugolib.IntegrationTestConfig) {
|
||||
cfg.WorkingDir = projectDir
|
||||
cfg.NeedsOsFS = true
|
||||
cfg.NeedsNpmInstall = true
|
||||
}),
|
||||
hugolib.TestOptInfo(),
|
||||
)
|
||||
|
||||
b.AssertFileContent("public/index.html",
|
||||
"RelPermalink: /css/styles.css|HasBody: true|",
|
||||
)
|
||||
b.AssertLogContains(tt.configFileName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// See Issue 13987.
|
||||
func TestTransformPostCSSESMConfigInModule(t *testing.T) {
|
||||
if !htesting.IsCI() {
|
||||
|
||||
Reference in New Issue
Block a user