This commit adds a new `vars` option to both the Sass transpilers (Dart Sass and Libsass).
This means that you can pass a map with key/value pairs to the transpiler:
```handlebars
{{ $vars := dict "$color1" "blue" "$color2" "green" "$font_size" "24px" }}
{{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }}
{{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }}
```
And the the variables will be available in the `hugo:vars` namespace. Example usage for Dart Sass:
```scss
@use "hugo:vars" as v;
p {
color: v.$color1;
font-size: v.$font_size;
}
```
Note that Libsass does not support the `use` keyword, so you need to `import` them as global variables:
```scss
@import "hugo:vars";
p {
color: $color1;
font-size: $font_size;
}
```
Hugo will:
* Add a missing leading `$` for the variable names if needed.
* Wrap the values in `unquote('VALUE')` (Sass built-in) to get proper handling of identifiers vs other strings.
This means that you can pull variables directly from e.g. the site config:
```toml
[params]
[params.sassvars]
color1 = "blue"
color2 = "green"
font_size = "24px"
image = "images/hero.jpg"
```
```handlebars
{{ $vars := site.Params.sassvars}}
{{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }}
{{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }}
```
Fixes#10555
This fixes the cases where
```js
import 'imp2/index.js';
import 'imp3/foo.js';
```
And these files lives in `assets` as:
```
imp2/index.ts
imp3/foo.ts
```
Fixes#10527
Simple sites may only have one css file. Update the replace directive to
correctly match single-file sourcemaps and multi-file sourcemaps.
Verified locally with and without SASS and CSS imports.
Fixes#8174
Same logic as for `index.{js,ts...}` files applies; if both `index.esm.js` and `index.js` exists (unlikely), you need to use the name
with extension when importing, else the `index.js` will win.
Fixes#8631
By using the input map as the basis, which means the hash will not change if we add/rename/remove options.
This happened in Hugo 0.99, as we added a new options. This is unortunate.
Unfortunately this means that the cache keys for PostCSS will change one more time in 0.100, but will be stable going forward.
Note that we have implemented this pattern in all the other resource transformers.
Updates #9787
Note that we will now fail if `inlineImports` is enabled and we cannot resolve an import.
You can work around this by either:
* Use url imports or imports with media queries.
* Set `skipInlineImportsNotFound=true` in the options
Also get the argument order in the different NewFileError* funcs in line.
Fixes#9895
* Redo the server error template
* Always add the content file context if relevant
* Remove some now superflous error string matching
* Move the server error template to _server/error.html
* Add file context (with position) to codeblock render blocks
* Improve JS build errors
Fixes#9892Fixes#9891Fixes#9893
* Add file context to minifier errors when publishing
* Misc fixes (see issues)
* Allow custom server error template in layouts/server/error.html
To get to this, this commit also cleans up and simplifies the code surrounding errors and files. This also removes the usage of `github.com/pkg/errors`, mostly because of https://github.com/pkg/errors/issues/223 -- but also because most of this is now built-in to Go.
Fixes#9852Fixes#9857Fixes#9863
* @warn and Sass deprecations are printed as WARN
* @debug is currently logged as INFO (needs the `--verbose` flag). We may adjust this if it gets too chatty.
Fixes#9683
This ommmit contains some security hardening measures for the Hugo build runtime.
There are some rarely used features in Hugo that would be good to have disabled by default. One example would be the "external helpers".
For `asciidoctor` and some others we use Go's `os/exec` package to start a new process.
These are a predefined set of binary names, all loaded from `PATH` and with a predefined set of arguments. Still, if you don't use `asciidoctor` in your project, you might as well have it turned off.
You can configure your own in the new `security` configuration section, but the defaults are configured to create a minimal amount of site breakage. And if that do happen, you will get clear instructions in the loa about what to do.
The default configuration is listed below. Note that almost all of these options are regular expression _whitelists_ (a string or a slice); the value `none` will block all.
```toml
[security]
enableInlineShortcodes = false
[security.exec]
allow = ['^dart-sass-embedded$', '^go$', '^npx$', '^postcss$']
osEnv = ['(?i)^(PATH|PATHEXT|APPDATA|TMP|TEMP|TERM)$']
[security.funcs]
getenv = ['^HUGO_']
[security.http]
methods = ['(?i)GET|POST']
urls = ['.*']
```
Previously, *minifyTransformation.Transform suppressed the
error returned by t.m.Minify. This meant that when minification
returned an error, the error would not reach the user. Instead,
minification would silently fail. For example, if a JavaScript
file included a call to the Date constructor with:
new Date(2020, 04, 02)
The package that the minification library uses to parse JS files,
github.com/tdewolff/parse would return an error, since "04" would
be parsed as a legacy octal. However, the JS file would remain
un-minified with no error.
Fixing this is not as simple as replacing "_" with an "err" in
*minifyTransformation.Transform, however (though this is
necessary). If we only returned this error from Transform,
then hugolib.TestResourceMinifyDisabled would fail. Instead of
being a no-op, as TestResourceMinifyDisabled expects, using the
"minify" template function with a "disableXML=true" config
setting instead returns the error, "minifier does not exist for
mimetype."
The "minifier does not exist" error is returned because of the
way minifiers.New works. If the user's config disables
minification for a particular MIME type, minifiers.New does
not add it to the resulting Client's *minify.M. However, this
also means that when the "minify" template function is executed,
a *resourceAdapter's transformations still add a minification.
When it comes time to call the minify.Minifier for a specific
MIME type via *M.MinifyMimetype, the github.com/tdewolff/minify
library throws the "does not exist" error for the missing MIME
type.
The solution was to change minifiers.New so, instead of skipping
a minifier for each disabled MIME type, it adds a NoOpMinifier,
which simply copies the source to the destination without
minification. This means that when the "minify" template
function is used for a particular resource, and that resource's
MIME type has minification disabled, minification is genuinely
skipped, and does not result in an error.
In order to add this, I've fixed a possibly unwanted interaction
between minifiers.TestConfigureMinify and
hugolib.TestResourceMinifyDisabled. The latter disables
minification and expects minification to be a no-op. The former
disables minification and expects it to result in an error. The
only reason hugolib.TestResourceMinifyDisabled passes in the
original code is that the "does not exist" error is suppressed.
However, we shouldn't suppress minification errors, since they
can leave users perplexed. I've changed the test assertion in
minifiers.TestConfigureMinify to expect no errors and a no-op
if minification is disabled for a particular MIME type.
Fixes#8954
This is in line with how both Node and ESBuild's native import resolver does it.
The ambiguous situations above were discovered trying to build AlpineJS v3.
Note that the above was never an issue if you used `./foo.js` and similar to import the component.
Fixes#8945
This commit started out investigating a `concurrent map read write` issue, ending by replacing the map with a struct.
This is easier to reason about, and it's more effective:
```
name old time/op new time/op delta
SiteNew/Regular_Deep_content_tree-16 71.5ms ± 3% 69.4ms ± 5% ~ (p=0.200 n=4+4)
name old alloc/op new alloc/op delta
SiteNew/Regular_Deep_content_tree-16 29.7MB ± 0% 27.9MB ± 0% -5.82% (p=0.029 n=4+4)
name old allocs/op new allocs/op delta
SiteNew/Regular_Deep_content_tree-16 313k ± 0% 303k ± 0% -3.35% (p=0.029 n=4+4)
```
See #8749
The main motivation behind this is simplicity and correctnes, but the new small config library is also faster:
```
BenchmarkDefaultConfigProvider/Viper-16 252418 4546 ns/op 2720 B/op 30 allocs/op
BenchmarkDefaultConfigProvider/Custom-16 450756 2651 ns/op 1008 B/op 6 allocs/op
```
Fixes#8633Fixes#8618Fixes#8630
Updates #8591Closes#6680Closes#5192
This commit fixes some issues where modules in /assets share the same name as in node_modules.
This was not intended, and with this commit the node_modules-components should be isolated. If you want to redefine something inside node_modules, use the `defines` option.
Fixes#7948
Updates #7777
Added support to allow SourceMap files to be external to the build.
In addition added more information when the js compilation has an error.
Correctly append sourceMappingURL to output file.
Fix merge conflict.
This change is mostly motivated to get a more stable CI build (we're building the Hugo site there, with Instagram and Twitter shortcodes sometimes failing).
Fixes#7866
This commit also introduces a convention where these common JS config files, including `package.hugo.json`, gets mounted into:
```
assets/_jsconfig
´``
These files mapped to their real filename will be added to the environment when running PostCSS, Babel etc., so you can do `process.env.HUGO_FILE_TAILWIND_CONFIG_JS` to resolve the real filename.
But do note that `assets` is a composite/union filesystem, so if your config file is not meant to be overridden, name them something specific.
This commit also adds adds `workDir/node_modules` to `NODE_PATH` and `HUGO_WORKDIR` to the env when running the JS tools above.
Fixes#7644Fixes#7656Fixes#7675
Added a flag to allow turning on sourcemap in ESBuild. The current support
can only support inline or true as value for sourcemap. This is because
the way ESBuild is invoked it doesn't have a separate output path
to write the mapfile external to the asset pipeline. Add disable for "" and "0".
Add test script and make sure mage check passes.
Fixes#7607
Add a new pipe called TranspileJS which uses the Babel cli. This makes it possible for users to write ES6 JavaScript code and transpile it to ES5 during website generation so that the code still works with older browser versions.
Fixes#5764
This more or less completes the simplification of the template handling code in Hugo started in v0.62.
The main motivation was to fix a long lasting issue about a crash in HTML content files without front matter.
But this commit also comes with a big functional improvement.
As we now have moved the base template evaluation to the build stage we now use the same lookup rules for `baseof` as for `list` etc. type of templates.
This means that in this simple example you can have a `baseof` template for the `blog` section without having to duplicate the others:
```
layouts
├── _default
│ ├── baseof.html
│ ├── list.html
│ └── single.html
└── blog
└── baseof.html
```
Also, when simplifying code, you often get rid of some double work, as shown in the "site building" benchmarks below.
These benchmarks looks suspiciously good, but I have repeated the below with ca. the same result. Compared to master:
```
name old time/op new time/op delta
SiteNew/Bundle_with_image-16 13.1ms ± 1% 10.5ms ± 1% -19.34% (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16 13.0ms ± 0% 10.7ms ± 1% -18.05% (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16 46.4ms ± 2% 43.1ms ± 1% -7.15% (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16 52.2ms ± 2% 47.8ms ± 1% -8.30% (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16 77.9ms ± 1% 70.9ms ± 1% -9.01% (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16 43.0ms ± 0% 37.2ms ± 1% -13.54% (p=0.029 n=4+4)
SiteNew/Page_collections-16 58.2ms ± 1% 52.4ms ± 1% -9.95% (p=0.029 n=4+4)
name old alloc/op new alloc/op delta
SiteNew/Bundle_with_image-16 3.81MB ± 0% 2.22MB ± 0% -41.70% (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16 3.60MB ± 0% 2.01MB ± 0% -44.20% (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16 19.3MB ± 1% 14.1MB ± 0% -26.91% (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16 70.7MB ± 0% 69.0MB ± 0% -2.40% (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16 37.1MB ± 0% 31.2MB ± 0% -15.94% (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16 17.6MB ± 0% 10.6MB ± 0% -39.92% (p=0.029 n=4+4)
SiteNew/Page_collections-16 25.9MB ± 0% 21.2MB ± 0% -17.99% (p=0.029 n=4+4)
name old allocs/op new allocs/op delta
SiteNew/Bundle_with_image-16 52.3k ± 0% 26.1k ± 0% -50.18% (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16 52.3k ± 0% 26.1k ± 0% -50.16% (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16 336k ± 1% 269k ± 0% -19.90% (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16 422k ± 0% 395k ± 0% -6.43% (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16 401k ± 0% 313k ± 0% -21.79% (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16 247k ± 0% 143k ± 0% -42.17% (p=0.029 n=4+4)
SiteNew/Page_collections-16 282k ± 0% 207k ± 0% -26.55% (p=0.029 n=4+4)
```
Fixes#6716Fixes#6760Fixes#6768Fixes#6778
This is a big commit, but it deletes lots of code and simplifies a lot.
* Resolving the template funcs at execution time means we don't have to create template clones per site
* Having a custom map resolver means that we can remove the AST lower case transformation for the special lower case Params map
Not only is the above easier to reason about, it's also faster, especially if you have more than one language, as in the benchmark below:
```
name old time/op new time/op delta
SiteNew/Deep_content_tree-16 53.7ms ± 0% 48.1ms ± 2% -10.38% (p=0.029 n=4+4)
name old alloc/op new alloc/op delta
SiteNew/Deep_content_tree-16 41.0MB ± 0% 36.8MB ± 0% -10.26% (p=0.029 n=4+4)
name old allocs/op new allocs/op delta
SiteNew/Deep_content_tree-16 481k ± 0% 410k ± 0% -14.66% (p=0.029 n=4+4)
```
This should be even better if you also have lots of templates.
Closes#6594
This commit pulls most of the image related logic into its own package, to make it easier to reason about and extend.
This is also a rewrite of the transformation logic used in Hugo Pipes, mostly to allow constructs like the one below:
{{ ($myimg | fingerprint ).Width }}
Fixes#5903Fixes#6234Fixes#6266
This commit implements Hugo Modules.
This is a broad subject, but some keywords include:
* A new `module` configuration section where you can import almost anything. You can configure both your own file mounts nd the file mounts of the modules you import. This is the new recommended way of configuring what you earlier put in `configDir`, `staticDir` etc. And it also allows you to mount folders in non-Hugo-projects, e.g. the `SCSS` folder in the Bootstrap GitHub project.
* A module consists of a set of mounts to the standard 7 component types in Hugo: `static`, `content`, `layouts`, `data`, `assets`, `i18n`, and `archetypes`. Yes, Theme Components can now include content, which should be very useful, especially in bigger multilingual projects.
* Modules not in your local file cache will be downloaded automatically and even "hot replaced" while the server is running.
* Hugo Modules supports and encourages semver versioned modules, and uses the minimal version selection algorithm to resolve versions.
* A new set of CLI commands are provided to manage all of this: `hugo mod init`, `hugo mod get`, `hugo mod graph`, `hugo mod tidy`, and `hugo mod vendor`.
All of the above is backed by Go Modules.
Fixes#5973Fixes#5996Fixes#6010Fixes#5911Fixes#5940Fixes#6074Fixes#6082Fixes#6092