get-esbuild-options.html 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. {{/*
  2. ## Overview
  3. This helper returns options dictionary used to configure ESBuild.
  4. The following configurations are set:
  5. * Enable JS minification.
  6. * Enable source map if not building for production.
  7. * Prepare `process.env.<ENVIRONMENT VARIABLE>` defines based on enabled features.
  8. This allows ESBuild to optimize JS bundle size by removing code related
  9. to unused features.
  10. * Added `process-shim.js` so `process.env` is defined.
  11. This way we don't have to explicitly specify every environment
  12. variable via `defines` value.
  13. * Prepare `params` for feature and service configs used in JS.
  14. For more details on ESBuild configuration, see: https://gohugo.io/hugo-pipes/js/
  15. ## Detailed Concepts
  16. ### `feature` and `service`
  17. Features configured in site wide `config.yml` file under `params.features` section.
  18. A **feature** provides a certain functionality to the user via one or more services.
  19. A feature be can enabled or disabled.
  20. A **service** is a 3rd party service, or JS library that implements a feature.
  21. For example, `analytics` is considered a feature.
  22. There are many services that can provide this feature, to name a few:
  23. * Google Analytics
  24. * Counter.Dev
  25. * GoatCounter
  26. To maximize extendibility and therefore usefulness as an open source project,
  27. it is important to define a standard interface that is easy to understand,
  28. configure, and extend.
  29. In this file, I took the liberty of standardizing this interface under `params.features`.
  30. Please note that this breaks compatibility with previous versions of `config.yaml`.
  31. I will provide sample `config.yaml` files with fully documented features, as well as
  32. documentation on migrating the `config.yaml` file to the new standard.
  33. Here is a sample config file for the new `params.features` section. Notice that each `service`
  34. is a dictionary with `enable` and `services` key. `services` is a dictionary with each key
  35. corresponding to a concrete service, and value as configuration / settings. In the case of
  36. services that need no configuration, an empty dictionary is created.
  37. ```yml
  38. params:
  39. features:
  40. # This is the `analytics` feature
  41. analytics:
  42. # This feature is enabled
  43. enable: true
  44. # List of services to enable
  45. services:
  46. # Google Analytics is enabled
  47. google:
  48. # settings for Google Analytics
  49. id: G-xxxxx
  50. # # Counter Dev is disabled
  51. # counterDev:
  52. # id: foo
  53. # name: bar
  54. # The `darkMode` feature
  55. darkmode:
  56. enable: true
  57. services:
  58. # darkmode is realized by using DarkReader library
  59. darkreader:
  60. # options are 'system', 'dark', 'light'
  61. defaultColorScheme: system
  62. # For all available options, see `interface DynamicThemeFix`:
  63. # https://github.com/darkreader/darkreader/blob/main/index.d.ts#L125
  64. fixes:
  65. invert: ['img[src$=".svg"]'] # inverts svg colors.
  66. # For all available options, see `interface Theme` in:
  67. # https://github.com/darkreader/darkreader/blob/main/index.d.ts#L45
  68. theme:
  69. brightness: 100
  70. contrast: 100
  71. sepia: 0
  72. ```
  73. This helper will convert the above config into the following env vars:
  74. * `FEATURE_ANALYTICS=1`
  75. * `FEATURE_ANALYTICS_GOOGLE=1`
  76. * `FEATURE_DARKMODE=1`
  77. * `FEATURE_DARKMODE_DARKREADER=1`
  78. In JS, you can use it like this:
  79. ```js
  80. import * as params from '@params';
  81. if (process.env.FEATURE_ANALYTICS) {
  82. // Do things to enable this feature here
  83. if (process.env.FEATURE_ANALYTICS_GOOGLE) {
  84. // Do things things to enable google analytics
  85. }
  86. }
  87. ```
  88. You can also access service configs via params:
  89. ```js
  90. import * as params from '@params';
  91. console.log(params);
  92. ```
  93. You will see console output like below. Note, each service configuration is
  94. namespaced by their corresponding feature.
  95. ```json
  96. {
  97. "analytics": {
  98. "google": {
  99. "id": "G-xxxxx"
  100. }
  101. },
  102. "darkmode": {
  103. "darkreader": {
  104. "defaultColorScheme": "system",
  105. "fixes": {
  106. "invert": "['img[src$=\".svg\"]']"
  107. },
  108. "theme": {
  109. "brightness": 100,
  110. "contrast": 100,
  111. "sepia": 0
  112. }
  113. }
  114. }
  115. }
  116. ```
  117. */}}
  118. {{/* Holds all the feature flag environment variables for `process.env.*` in JS land */}}
  119. {{ $defines := dict }}
  120. {{/* Holds all the feature configuration variables exposed to JS side */}}
  121. {{ $params := dict }}
  122. {{/* set NODE_ENV depending on if we are building for production use. */}}
  123. {{ $defines = $defines | merge (dict
  124. "process.env.NODE_ENV" (cond hugo.IsProduction `"production"` `"development"` )
  125. )}}
  126. {{/* Go through each feature defined in our config.yml/config.toml/config.json file. */}}
  127. {{ range $feature, $featureDef := site.Params.features }}
  128. {{/* Initialize a dictionary that will hold all service configs for this specific feature */}}
  129. {{ $featureParams := dict }}
  130. {{ with $featureDef }}
  131. {{/* convert feature name to uppercase and remove '_', e.g. `darkMode` becomes `DARKMODE` */}}
  132. {{ $featureName := replace $feature "_" "" | upper }}
  133. {{/* The feature is enabled if the `enable` key is absent, or is set to `true` */}}
  134. {{ $featureEnabled := or (not (isset . "enable")) .enable }}
  135. {{/* Sets `FEATURE_<FEATURE_NAME>` env var to "1" or "0" depending on if the feature is enabled. */}}
  136. {{ $defines = $defines | merge (dict
  137. (printf "process.env.FEATURE_%s" $featureName) (cond $featureEnabled `'1'` `'0'`)
  138. ) }}
  139. {{ if $featureEnabled }}
  140. {{/* Loop through each service under this feature */}}
  141. {{ range $service, $config := .services }}
  142. {{/*
  143. We assume all services are enabled. To disable a service,
  144. simply comment it out from `config.yaml`.
  145. */}}
  146. {{/* Convert name to all uppercase, removing underscore */}}
  147. {{ $serviceName := replace $service "_" "" | upper }}
  148. {{/* let JS side know this service is enabled */}}
  149. {{ $defines = $defines | merge (dict
  150. (printf "process.env.FEATURE_%s_%s" $featureName $serviceName) `'1'`
  151. ) }}
  152. {{/* add service configuration to feature params */}}
  153. {{ $featureParams = $featureParams | merge (dict $service $config) }}
  154. {{ end }}
  155. {{/* add feature params to top level params */}}
  156. {{ $params = $params | merge (dict $feature $featureParams) }}
  157. {{ end }}
  158. {{ end }}
  159. {{ end }}
  160. {{
  161. return dict
  162. "defines" $defines
  163. "params" $params
  164. "minify" true
  165. "sourceMap" (cond hugo.IsProduction "" "inline")
  166. "inject" "scripts/process-shim.js"
  167. }}