mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
js: Add Shims option
This commit adds a new `shims` option to `js.Build` that allows swapping out a component with another. Fixes #8165
This commit is contained in:
parent
a1fe552fc9
commit
e19a046c4b
3 changed files with 46 additions and 35 deletions
|
@ -43,19 +43,42 @@ minify [bool]
|
||||||
avoidTDZ {{< new-in "0.78.0" >}}
|
avoidTDZ {{< new-in "0.78.0" >}}
|
||||||
: There is/was a bug in WebKit with severe performance issue with the tracking of TDZ checks in JavaScriptCore. Enabling this flag removes the TDZ and `const` assignment checks and may improve performance of larger JS codebases until the WebKit fix is in widespread use. See https://bugs.webkit.org/show_bug.cgi?id=199866
|
: There is/was a bug in WebKit with severe performance issue with the tracking of TDZ checks in JavaScriptCore. Enabling this flag removes the TDZ and `const` assignment checks and may improve performance of larger JS codebases until the WebKit fix is in widespread use. See https://bugs.webkit.org/show_bug.cgi?id=199866
|
||||||
|
|
||||||
|
shims {{< new-in "0.81.0" >}}
|
||||||
|
: This option allows swapping out a component with another. A common use case is to load dependencies like React from a CDN (with _shims_) when in production, but running with the full bundled `node_modules` dependency during development:
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ $shims := dict "react" "js/shims/react.js" "react-dom" "js/shims/react-dom.js" }}
|
||||||
|
{{ $js = $js | js.Build dict "shims" $shims }}
|
||||||
|
```
|
||||||
|
|
||||||
|
The _shim_ files may look like these:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// js/shims/react.js
|
||||||
|
module.exports = window.React;
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// js/shims/react-dom.js
|
||||||
|
module.exports = window.ReactDOM;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
With the above, these imports should work in both scenarios:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import * as React from 'react'
|
||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
```
|
||||||
|
|
||||||
target [string]
|
target [string]
|
||||||
: The language target.
|
: The language target.
|
||||||
One of: `es5`, `es2015`, `es2016`, `es2017`, `es2018`, `es2019`, `es2020` or `esnext`.
|
One of: `es5`, `es2015`, `es2016`, `es2017`, `es2018`, `es2019`, `es2020` or `esnext`.
|
||||||
Default is `esnext`.
|
Default is `esnext`.
|
||||||
|
|
||||||
externals [slice]
|
externals [slice]
|
||||||
: External dependencies. If a dependency should not be included in the bundle (Ex. library loaded from a CDN.), it should be listed here.
|
: External dependencies. Use this to trim dependencies you know will never be executed. See https://esbuild.github.io/api/#external
|
||||||
|
|
||||||
```go-html-template
|
|
||||||
{{ $externals := slice "react" "react-dom" }}
|
|
||||||
```
|
|
||||||
|
|
||||||
> Marking a package as external doesn't imply that the library can be loaded from a CDN. It simply tells Hugo not to expand/include the package in the JS file.
|
|
||||||
|
|
||||||
defines [map]
|
defines [map]
|
||||||
: Allow to define a set of string replacement to be performed when building. Should be a map where each key is to be replaced by its value.
|
: Allow to define a set of string replacement to be performed when building. Should be a map where each key is to be replaced by its value.
|
||||||
|
@ -145,29 +168,4 @@ Or with options:
|
||||||
<script type="text/javascript" src="{{ $built.RelPermalink }}" defer></script>
|
<script type="text/javascript" src="{{ $built.RelPermalink }}" defer></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Shimming a JS library
|
|
||||||
|
|
||||||
It's a common practice to load external libraries using a content delivery network (CDN) rather than importing all packages in a single JS file. To load scripts from a CDN with Hugo, you'll need to shim the libraries as follows. In this example, `react` and `react-dom` will be shimmed.
|
|
||||||
|
|
||||||
First, add React and ReactDOM [CDN script tags](https://reactjs.org/docs/add-react-to-a-website.html#tip-minify-javascript-for-production) in your HTML template files. Then create `assets/js/shims/react.js` and `assets/js/shims/react-dom.js` with the following contents:
|
|
||||||
```js
|
|
||||||
// In assets/js/shims/react.js
|
|
||||||
module.exports = window.React;
|
|
||||||
|
|
||||||
// In assets/js/shims/react-dom.js
|
|
||||||
module.exports = window.ReactDOM;
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, add the following to your project's `package.json`:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"browser": {
|
|
||||||
"react": "./assets/js/shims/react.js",
|
|
||||||
"react-dom": "./assets/js/shims/react-dom.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This tells Hugo's `js.Build` command to look for `react` and `react-dom` in the project's `assets/js/shims` folder. Note that the `browser` field in your `package.json` file will cause React and ReactDOM to be excluded from your JavaScript bundle. Therefore, **it is unnecessary to add them to the `js.Build` command's `externals` argument.**
|
|
||||||
|
|
||||||
That's it! You should now have a browser-friendly JS which can use external JS libraries.
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ path="github.com/gohugoio/hugoTestProjectJSModImports"
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require github.com/gohugoio/hugoTestProjectJSModImports v0.5.0 // indirect
|
require github.com/gohugoio/hugoTestProjectJSModImports v0.8.0 // indirect
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
@ -215,4 +215,9 @@ Hello3 from mod2. Date from date-fns: ${today}
|
||||||
Hello from lib in the main project
|
Hello from lib in the main project
|
||||||
Hello5 from mod2.
|
Hello5 from mod2.
|
||||||
var myparam = "Hugo Rocks!";`)
|
var myparam = "Hugo Rocks!";`)
|
||||||
|
|
||||||
|
// React JSX, verify the shimming.
|
||||||
|
b.AssertFileContent("public/js/like.js", `@v0.8.0/assets/js/shims/react.js
|
||||||
|
module.exports = window.ReactDOM;
|
||||||
|
`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,11 +62,14 @@ type Options struct {
|
||||||
Format string
|
Format string
|
||||||
|
|
||||||
// External dependencies, e.g. "react".
|
// External dependencies, e.g. "react".
|
||||||
Externals []string `hash:"set"`
|
Externals []string
|
||||||
|
|
||||||
// User defined symbols.
|
// User defined symbols.
|
||||||
Defines map[string]interface{}
|
Defines map[string]interface{}
|
||||||
|
|
||||||
|
// Maps a component import to another.
|
||||||
|
Shims map[string]string
|
||||||
|
|
||||||
// User defined params. Will be marshaled to JSON and available as "@params", e.g.
|
// User defined params. Will be marshaled to JSON and available as "@params", e.g.
|
||||||
// import * as params from '@params';
|
// import * as params from '@params';
|
||||||
Params interface{}
|
Params interface{}
|
||||||
|
@ -138,6 +141,13 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
|
||||||
fs := c.rs.Assets
|
fs := c.rs.Assets
|
||||||
|
|
||||||
resolveImport := func(args api.OnResolveArgs) (api.OnResolveResult, error) {
|
resolveImport := func(args api.OnResolveArgs) (api.OnResolveResult, error) {
|
||||||
|
impPath := args.Path
|
||||||
|
if opts.Shims != nil {
|
||||||
|
override, found := opts.Shims[impPath]
|
||||||
|
if found {
|
||||||
|
impPath = override
|
||||||
|
}
|
||||||
|
}
|
||||||
isStdin := args.Importer == stdinImporter
|
isStdin := args.Importer == stdinImporter
|
||||||
var relDir string
|
var relDir string
|
||||||
if !isStdin {
|
if !isStdin {
|
||||||
|
@ -153,8 +163,6 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
|
||||||
relDir = filepath.Dir(opts.sourcefile)
|
relDir = filepath.Dir(opts.sourcefile)
|
||||||
}
|
}
|
||||||
|
|
||||||
impPath := args.Path
|
|
||||||
|
|
||||||
// Imports not starting with a "." is assumed to live relative to /assets.
|
// Imports not starting with a "." is assumed to live relative to /assets.
|
||||||
// Hugo makes no assumptions about the directory structure below /assets.
|
// Hugo makes no assumptions about the directory structure below /assets.
|
||||||
if relDir != "" && strings.HasPrefix(impPath, ".") {
|
if relDir != "" && strings.HasPrefix(impPath, ".") {
|
||||||
|
|
Loading…
Reference in a new issue