Bundling JS with ESBuild (#702)
* add npm dependencies used in this theme * implement helper to configure JS and ESBuild * migrate jquery popper.js bootstrap fontawesome to js bundle * refactor main.js into smaller pieces, and moved navbar.js to assets * remove list.js. It adjusts post card height to be the same, but is actually not needed. * refactored notes.js, search.js, single.js into application.js * move ityped to js asset, implement experiences horizontal vertical line in css * align recent post height via css * migrated home.js and refactored into various sections * migrated darkMode feature to js bundle * moved mermaid feature to js bundle * migrate syntax highlight to js bundle * migrate katex ( js portion ) to js bundle * migrate pdf-js to js bundle by delegating to cdn * set explicit comparisions for feature envvars so js can properly optimize * removed goat-counter * more fixes for broken achievements and small bugs * more bug fixes * allow configuration of hightlight.js, fix video-player shortcode * remove jquery all together * add null handling and fix merge conflicts Co-authored-by: Aaron Qian <aaron@yeet.io>
This commit is contained in:
parent
fe14b0fbf5
commit
02db3d3044
491 changed files with 4919 additions and 151344 deletions
209
layouts/partials/helpers/get-esbuild-options.html
Normal file
209
layouts/partials/helpers/get-esbuild-options.html
Normal file
|
@ -0,0 +1,209 @@
|
|||
{{/*
|
||||
|
||||
## Overview
|
||||
|
||||
This helper returns options dictionary used to configure ESBuild.
|
||||
The following configurations are set:
|
||||
|
||||
* Enable JS minification.
|
||||
* Enable source map if not building for production.
|
||||
* Prepare `process.env.<ENVIRONMENT VARIABLE>` defines based on enabled features.
|
||||
This allows ESBuild to optimize JS bundle size by removing code related
|
||||
to unused features.
|
||||
* Added `process-shim.js` so `process.env` is defined.
|
||||
This way we don't have to explicitly specify every environment
|
||||
variable via `defines` value.
|
||||
* Prepare `params` for feature and service configs used in JS.
|
||||
|
||||
For more details on ESBuild configuration, see: https://gohugo.io/hugo-pipes/js/
|
||||
|
||||
## Detailed Concepts
|
||||
|
||||
### `feature` and `service`
|
||||
|
||||
Features configured in site wide `config.yml` file under `params.features` section.
|
||||
A **feature** provides a certain functionality to the user via one or more services.
|
||||
A feature be can enabled or disabled.
|
||||
|
||||
A **service** is a 3rd party service, or JS library that implements a feature.
|
||||
|
||||
For example, `analytics` is considered a feature.
|
||||
There are many services that can provide this feature, to name a few:
|
||||
|
||||
* Google Analytics
|
||||
* Counter.Dev
|
||||
* GoatCounter
|
||||
|
||||
To maximize extendibility and therefore usefulness as an open source project,
|
||||
it is important to define a standard interface that is easy to understand,
|
||||
configure, and extend.
|
||||
|
||||
In this file, I took the liberty of standardizing this interface under `params.features`.
|
||||
Please note that this breaks compatibility with previous versions of `config.yaml`.
|
||||
I will provide sample `config.yaml` files with fully documented features, as well as
|
||||
documentation on migrating the `config.yaml` file to the new standard.
|
||||
|
||||
Here is a sample config file for the new `params.features` section. Notice that each `service`
|
||||
is a dictionary with `enable` and `services` key. `services` is a dictionary with each key
|
||||
corresponding to a concrete service, and value as configuration / settings. In the case of
|
||||
services that need no configuration, an empty dictionary is created.
|
||||
|
||||
```yml
|
||||
params:
|
||||
features:
|
||||
|
||||
# This is the `analytics` feature
|
||||
analytics:
|
||||
# This feature is enabled
|
||||
enable: true
|
||||
# List of services to enable
|
||||
services:
|
||||
|
||||
# Google Analytics is enabled
|
||||
google:
|
||||
# settings for Google Analytics
|
||||
id: G-xxxxx
|
||||
|
||||
# # Counter Dev is disabled
|
||||
# counterDev:
|
||||
# id: foo
|
||||
# name: bar
|
||||
|
||||
# The `darkMode` feature
|
||||
darkmode:
|
||||
enable: true
|
||||
services:
|
||||
# darkmode is realized by using DarkReader library
|
||||
darkreader:
|
||||
# options are 'system', 'dark', 'light'
|
||||
defaultColorScheme: system
|
||||
# For all available options, see `interface DynamicThemeFix`:
|
||||
# https://github.com/darkreader/darkreader/blob/main/index.d.ts#L125
|
||||
fixes:
|
||||
invert: ['img[src$=".svg"]'] # inverts svg colors.
|
||||
# For all available options, see `interface Theme` in:
|
||||
# https://github.com/darkreader/darkreader/blob/main/index.d.ts#L45
|
||||
theme:
|
||||
brightness: 100
|
||||
contrast: 100
|
||||
sepia: 0
|
||||
```
|
||||
|
||||
This helper will convert the above config into the following env vars:
|
||||
|
||||
* `FEATURE_ANALYTICS=1`
|
||||
* `FEATURE_ANALYTICS_GOOGLE=1`
|
||||
* `FEATURE_DARKMODE=1`
|
||||
* `FEATURE_DARKMODE_DARKREADER=1`
|
||||
|
||||
In JS, you can use it like this:
|
||||
|
||||
```js
|
||||
import * as params from '@params';
|
||||
|
||||
if (process.env.FEATURE_ANALYTICS) {
|
||||
// Do things to enable this feature here
|
||||
|
||||
if (process.env.FEATURE_ANALYTICS_GOOGLE) {
|
||||
// Do things things to enable google analytics
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also access service configs via params:
|
||||
|
||||
```js
|
||||
import * as params from '@params';
|
||||
|
||||
console.log(params);
|
||||
```
|
||||
|
||||
You will see console output like below. Note, each service configuration is
|
||||
namespaced by their corresponding feature.
|
||||
|
||||
```json
|
||||
{
|
||||
"analytics": {
|
||||
"google": {
|
||||
"id": "G-xxxxx"
|
||||
}
|
||||
},
|
||||
"darkmode": {
|
||||
"darkreader": {
|
||||
"defaultColorScheme": "system",
|
||||
"fixes": {
|
||||
"invert": "['img[src$=\".svg\"]']"
|
||||
},
|
||||
"theme": {
|
||||
"brightness": 100,
|
||||
"contrast": 100,
|
||||
"sepia": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
*/}}
|
||||
|
||||
{{/* Holds all the feature flag environment variables for `process.env.*` in JS land */}}
|
||||
{{ $defines := dict }}
|
||||
|
||||
{{/* Holds all the feature configuration variables exposed to JS side */}}
|
||||
{{ $params := dict }}
|
||||
|
||||
{{/* set NODE_ENV depending on if we are building for production use. */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
"process.env.NODE_ENV" (cond hugo.IsProduction `"production"` `"development"` )
|
||||
)}}
|
||||
|
||||
{{/* Go through each feature defined in our config.yml/config.toml/config.json file. */}}
|
||||
{{ range $feature, $featureDef := site.Params.features }}
|
||||
{{/* Initialize a dictionary that will hold all service configs for this specific feature */}}
|
||||
{{ $featureParams := dict }}
|
||||
|
||||
{{ with $featureDef }}
|
||||
{{/* convert feature name to uppercase and remove '_', e.g. `darkMode` becomes `DARKMODE` */}}
|
||||
{{ $featureName := replace $feature "_" "" | upper }}
|
||||
|
||||
{{/* The feature is enabled if the `enable` key is absent, or is set to `true` */}}
|
||||
{{ $featureEnabled := or (not (isset . "enable")) .enable }}
|
||||
|
||||
{{/* Sets `FEATURE_<FEATURE_NAME>` env var to "1" or "0" depending on if the feature is enabled. */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
(printf "process.env.FEATURE_%s" $featureName) (cond $featureEnabled `'1'` `'0'`)
|
||||
) }}
|
||||
|
||||
{{ if $featureEnabled }}
|
||||
{{/* Loop through each service under this feature */}}
|
||||
{{ range $service, $config := .services }}
|
||||
{{/*
|
||||
We assume all services are enabled. To disable a service,
|
||||
simply comment it out from `config.yaml`.
|
||||
*/}}
|
||||
|
||||
{{/* Convert name to all uppercase, removing underscore */}}
|
||||
{{ $serviceName := replace $service "_" "" | upper }}
|
||||
|
||||
{{/* let JS side know this service is enabled */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
(printf "process.env.FEATURE_%s_%s" $featureName $serviceName) `'1'`
|
||||
) }}
|
||||
|
||||
{{/* add service configuration to feature params */}}
|
||||
{{ $featureParams = $featureParams | merge (dict $service $config) }}
|
||||
{{ end }}
|
||||
|
||||
{{/* add feature params to top level params */}}
|
||||
{{ $params = $params | merge (dict $feature $featureParams) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{
|
||||
return dict
|
||||
"defines" $defines
|
||||
"params" $params
|
||||
"minify" true
|
||||
"sourceMap" (cond hugo.IsProduction "" "inline")
|
||||
"inject" "scripts/process-shim.js"
|
||||
}}
|
Loading…
Add table
Add a link
Reference in a new issue