@massimo-cassandro/minimo 1.40.0 → 1.40.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,7 +15,7 @@ export const default_params = {
15
15
 
16
16
  // directory output (percorso relativo alla dir di lavoro)
17
17
  // se la dir non esiste, viene creata
18
- output_dir: './output',
18
+ output_dir: './output', // symfony -> '../../public',
19
19
 
20
20
 
21
21
  // WEBMANIFEST
@@ -43,12 +43,12 @@ export const default_params = {
43
43
  // nome del file snippet, compresa l'estensione
44
44
  // se questo parametro è null e anche `snippet_target_file` lo è, lo snippet non viene generato
45
45
  // se il linguaggio è ejs il nome è sempre 'favicons.incl.ejs' e snippet_name viene ignorato
46
- snippet_name: 'favicons.html',
46
+ snippet_name: 'favicons.html', // symfony -> 'favicons.incl.html.twig',
47
47
 
48
48
  // path (relativo a questo file) in cui salvare lo snippet
49
49
  // se null, viene utilizzato lo stesso percorso indicato in `output_dir`
50
50
  // se la dir non esiste, viene creata
51
- snippet_path: null,
51
+ snippet_path: null, // symfony -> '../../templates/_incl',
52
52
 
53
53
  // path del file in cui scrivere le righe dello snippet
54
54
  // questa impostazione è alternativa alle due precedenti e, se presente, queste
@@ -62,7 +62,7 @@ export const default_params = {
62
62
 
63
63
  // linguaggio da utilizzare per la sintassi dello snippet html
64
64
  // html, pug, ejs
65
- snippet_language: 'ejs',
65
+ snippet_language: 'ejs', // symfony: 'html',
66
66
 
67
67
  // template per la costruzione dello snippet.
68
68
  // si tratta di una stringa (anche su più righe) in cui deve essere presente
@@ -78,7 +78,7 @@ export const default_params = {
78
78
 
79
79
  // se true aggiunge allo snippet una query string per ovviare ad eventuali
80
80
  // problemi di caching del browser
81
- add_cache_buster: false,
81
+ add_cache_buster: false, // symfony: true,
82
82
 
83
83
  //****************************************************************************
84
84
 
@@ -114,7 +114,7 @@ const config = {
114
114
  // your project tokens — e.g. remaps a Figma/Penpot-exported `primary`
115
115
  // color to minimo's own `primary.100` naming
116
116
  {
117
- src: './project-tokens/*.{js,mjs,jsonc,json}',
117
+ src: './design-tokens/*.{js,mjs,jsonc,json}',
118
118
  prefix: 'my-project',
119
119
  transform: { primary: 'primary.100' },
120
120
  }
@@ -3,5 +3,5 @@
3
3
 
4
4
  */
5
5
 
6
- @import '@fontsource-variable/rubik/wght.css';
7
- @import '@fontsource-variable/rubik/wght-italic.css';
6
+ /* @import '@fontsource-variable/rubik/wght.css';
7
+ @import '@fontsource-variable/rubik/wght-italic.css'; */
@@ -22,3 +22,4 @@ node_modules
22
22
  _private
23
23
  public/_dev
24
24
  unresolved-unused-props.md
25
+ orphan-classes.md
@@ -22,7 +22,8 @@ class UnsplashController extends AbstractController
22
22
  $orientation = 'landscape';
23
23
  }
24
24
 
25
- $unsplash_access_key = 'xxxxxxx';
25
+ $unsplash_access_key = 'xxxxxxx'; // vedi minimo/_private/unsplash-access-keys.md
26
+
26
27
  $collections_ids = '3660951'; // comma separated list
27
28
  $count = null;
28
29
 
@@ -4,17 +4,22 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6
6
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7
- <title>{%- block title -%}{%- endblock %} | Marketing</title>
7
+ <title>{%- block title -%}{%- endblock %} | xxxxx</title>
8
8
  <meta name="robots" content="noindex, nofollow, noarchive">
9
9
  {%- include '_incl/favicons.incl.html.twig'-%}
10
+
11
+ <link rel="preload" href="{{ asset('fonts/xxxxx.woff2') }}" as="font" type="font/woff2" crossorigin>
12
+
10
13
  {{- '' -}}
14
+ {#- shared.js, runtime.js e shared.css servono solo con `useSharedChunk: true` in webpack.config.mjs:
15
+ con `false` rimuovere tutte le righe che li referenziano (qui sotto e a fine body) -#}
11
16
  <link rel="preload" href="{{ asset('index.js') }}" as="script">
12
17
  <link rel="preload" href="{{ asset('shared.js') }}" as="script">
13
18
  <link rel="preload" href="{{ asset('runtime.js') }}" as="script">
14
19
  {{- '' -}}
15
20
  <link rel="preload" href="{{ asset('shared.css') }}" as="style">
16
21
  <link rel="preload" href="{{ asset('index.css') }}" as="style">
17
- {# shared.css va linkato PRIMA del css della entry (ordine della cascata) #}
22
+ {# shared.css va inserito PRIMA del css della entry (ordine della cascata) #}
18
23
  <link rel="stylesheet" href="{{ asset('shared.css') }}" type="text/css" media="all">
19
24
  <link rel="stylesheet" href="{{ asset('index.css') }}" type="text/css" media="all">
20
25
  <style>
@@ -24,6 +29,8 @@
24
29
  </head>
25
30
  <body>
26
31
 
32
+ {%- block body -%}{%- endblock -%}
33
+
27
34
  <script src="{{ asset('runtime.js') }}"></script>
28
35
  <script src="{{ asset('shared.js') }}"></script>
29
36
  <script src="{{ asset('index.js') }}"></script>
@@ -1,6 +1,6 @@
1
1
  {#- https://symfony.com/doc/current/controller/error_pages.html#testing-error-pages-during-development -#}
2
2
  <!DOCTYPE html>
3
- <html lang="it" data-err-code="{{ status_code }}" data-err-text="{{ status_text}}">
3
+ <html lang="it" class="uspg" data-err-code="{{ status_code }}" data-err-text="{{ status_text}}">
4
4
  <head>
5
5
  <meta charset="utf-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
@@ -8,6 +8,10 @@
8
8
  <title>Errore {{ status_code }}</title>
9
9
  <meta name="robots" content="noindex, nofollow, noarchive">
10
10
  {%- include '_incl/favicons.incl.html.twig'-%}
11
+ {#- shared.css, shared.js e runtime.js servono solo con `useSharedChunk: true` in webpack.config.mjs:
12
+ con `false` rimuovere tutte le righe che li referenziano -#}
13
+ <link rel="preload" href="{{ asset('shared.css') }}" as="style">
14
+ <link rel="stylesheet" href="{{ asset('shared.css') }}" media="all">
11
15
  <link rel="preload" href="{{ asset('index.css') }}" as="style">
12
16
  <link rel="stylesheet" href="{{ asset('index.css') }}" media="all">
13
17
  <link rel="preload" href="{{ asset('error-pages.css') }}" as="style">
@@ -0,0 +1,17 @@
1
+ {% extends '_main-tpl.html.twig' %}
2
+
3
+ {% block title %}xxxx{% endblock %}
4
+ {% block head %}
5
+
6
+ <link rel="preload" href="{{ asset('__page__.css') }}" as="style">
7
+ <link rel="stylesheet" href="{{ asset('__page__.css') }}" media="all">
8
+ <link rel="preload" href="{{ asset('__page__.js') }}" as="script">
9
+ {% endblock %}
10
+ {% block js %}
11
+ <script src="{{ asset('__page__.js') }}"></script>
12
+ {% endblock %}
13
+
14
+ {% block body %}
15
+ home
16
+ <div id="root"><div class="spinner"></div></div>
17
+ {% endblock %}
@@ -19,7 +19,7 @@
19
19
  "scripts": {
20
20
  "webpack DEV (js)": "NODE_ENV=development webpack serve --config ./webpack.config.mjs #--open-app-name 'Google Chrome'",
21
21
  "php server": "php -S localhost:[[port8000]] # -t root_dir/",
22
- "webpack DEV (sf)": "rm -rf ./public/_dev && NODE_ENV=development webpack serve --config ./webpack.config.mjs # http://192.168.1.135:[[port5700]",
22
+ "webpack DEV (sf)": "rm -rf ./public/_dev && NODE_ENV=development webpack serve --config ./webpack.config.mjs # http://192.168.1.135:[[port5700]]",
23
23
  "symfony server": "symfony serve --port=[[port8000]] --listen-ip=0.0.0.0 # http://192.168.1.135:[[port8000]] # -d (deamon): rimane aperto anche dopo la chiusura del terminale, terminare con `symfony server:stop`",
24
24
  "launchChrome": "open -n -a 'Google Chrome' --args --profile-directory='Profile 3' # mbn: 1 / mg2: 3",
25
25
  "webpack PROD": "npm run 'UPD-version' && NODE_ENV=production webpack --config ./webpack.config.mjs --stats minimal",
@@ -1,5 +1,5 @@
1
1
  // webpack-config-modules/custom-props-purgecss-plugin.mjs
2
- // v.3
2
+ // v.3.1
3
3
  import fs from 'fs';
4
4
  import postcss from 'postcss';
5
5
  import { globSync } from 'glob';
@@ -11,7 +11,10 @@ import { globSync } from 'glob';
11
11
  custom properties disponibili. I css compilati da webpack contengono invece
12
12
  solo *usi* (`var(--nome)`), mai definizioni. Dopo la minificazione degli
13
13
  asset, il plugin:
14
- 1. scansiona i css di ogni "set" per trovare le custom properties usate;
14
+ 1. scansiona i css di ogni "set" per trovare le custom properties usate, e
15
+ anche i js dei chunk che contengono quei css (i css importati con `?raw`,
16
+ es. shadow DOM dei web components, sono stringhe nel bundle js: vengono
17
+ così rilevati solo per i componenti realmente importati);
15
18
  2. risolve le dipendenze transitive (`--a: calc(var(--b) * 2)` => anche
16
19
  `--b`, fino al fixed point, fallback `var(--x, var(--y))` inclusi);
17
20
  3. estrae dal master le sole definizioni necessarie, PRESERVANDO l'ordine
@@ -137,8 +140,9 @@ export class CustomPropsPurgeCssPlugin {
137
140
  * @param {string} [options.selector=':root'] - Selettore con cui sostituire i blocchi
138
141
  * `:root` del master (es. `':where(html)'`); gli altri selettori (temi, ecc.) restano invariati (default: ':root')
139
142
  * @param {string[]} [options.extraUsageGlobs=[]] - Glob di file css i cui usi di var()
140
- * contano come usati in TUTTI i set: css caricati fuori dagli asset (shadow DOM dei
141
- * web components, import `?raw`) (default: [])
143
+ * contano come usati in TUTTI i set: serve solo per css caricati fuori dal bundle
144
+ * (i css `?raw` sono già rilevati nei js dei chunk del set). Un glob troppo largo
145
+ * porta nel css anche le props di componenti non importati (default: [])
142
146
  * @param {(string|RegExp)[]} [options.seeds=[]] - Props da includere comunque in tutti i
143
147
  * set (nomi esatti o pattern risolti sui nomi dichiarati nel master), es. override
144
148
  * consumati da un altro asset (default: [])
@@ -248,9 +252,29 @@ export class CustomPropsPurgeCssPlugin {
248
252
  continue;
249
253
  }
250
254
 
251
- // props usate nei css del set
255
+ /*
256
+ asset da scansire: i css del set + i js dei chunk che li contengono
257
+ (e dei chunk da essi raggiunti). I css importati con `?raw` (shadow DOM
258
+ dei web components) sono stringhe nel bundle js: vengono quindi
259
+ rilevati solo per i componenti realmente importati
260
+ */
261
+ const scanned = new Set(sourceNames);
262
+ for (const chunk of compilation.chunks) {
263
+ if (![...chunk.files].some(file => sourceNames.includes(file))) {
264
+ continue;
265
+ }
266
+ for (const referenced of chunk.getAllReferencedChunks()) {
267
+ for (const file of referenced.files) {
268
+ if (/\.m?js$/i.test(file)) {
269
+ scanned.add(file);
270
+ }
271
+ }
272
+ }
273
+ }
274
+
275
+ // props usate negli asset scansionati
252
276
  const used = new Set(commonUsages);
253
- for (const name of sourceNames) {
277
+ for (const name of scanned) {
254
278
  varRefs(compilation.getAsset(name).source.source().toString()).forEach(ref => used.add(ref));
255
279
  }
256
280
 
@@ -1,5 +1,5 @@
1
1
  // webpack.config.mjs __project_name__
2
- // v.3
2
+ // v.3.1
3
3
  import path from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import webpack from 'webpack';
@@ -8,17 +8,21 @@ import * as process from 'process'; // Rende 'process' disponibile nel contesto
8
8
  // import { styleText } from 'node:util';
9
9
  // import { createRequire } from 'node:module';
10
10
 
11
+ // SETUP symfony -> commentare HtmlWebpackPlugin e HtmlWebpackInjectPreload
11
12
  import HtmlWebpackPlugin from 'html-webpack-plugin';
12
13
  import HtmlWebpackInjectPreload from '@principalstudio/html-webpack-inject-preload';
14
+
13
15
  import TerserPlugin from 'terser-webpack-plugin';
14
16
  import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
15
17
  import MiniCssExtractPlugin from 'mini-css-extract-plugin';
16
18
  import CopyWebpackPlugin from 'copy-webpack-plugin';
17
19
  // import Dotenv from 'dotenv-webpack';
18
20
  import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts';
19
- // import { WebpackManifestPlugin } from 'webpack-manifest-plugin';
20
21
  // import HtmlWebpackInjectAttributesPlugin from 'html-webpack-inject-attributes-plugin';
21
22
 
23
+ // NB: symfony -> decommentare WebpackManifestPlugin
24
+ // import { WebpackManifestPlugin } from 'webpack-manifest-plugin';
25
+
22
26
  import { cssRules } from './webpack-config-modules/css-rules.mjs';
23
27
  import { createPurgeCSSPlugins } from './webpack-config-modules/purgecss-setup.mjs';
24
28
  import { getJsConfigAliases } from './webpack-config-modules/get-jsConfig-aliases.mjs';
@@ -40,7 +44,8 @@ const __filename = fileURLToPath(import.meta.url)
40
44
 
41
45
  const isDevelopment = process.env.NODE_ENV === 'development'
42
46
  ,devServerPort = [[port5700]]
43
- ,apiPort = [[port8000]] // eslint-disable-line no-unused-vars
47
+ // SETUP symfony
48
+ // ,apiPort = [[port8000]]
44
49
  ,useSass = false
45
50
 
46
51
  // css in dev: true = iniettato con style-loader (veloce, nessun asset css);
@@ -48,7 +53,9 @@ const isDevelopment = process.env.NODE_ENV === 'development'
48
53
  // NB: con `purgeCssInDev: true` (vedi sotto) viene comunque forzato a false,
49
54
  // perché il purge e il plugin delle custom properties lavorano sugli asset css
50
55
  ,inlineCssInDevMode = true
51
- // sf: inlineCssInDevMode = false
56
+ // SETUP symfony
57
+ // ,inlineCssInDevMode = false
58
+
52
59
  ,useSvgo = true
53
60
  ,useSvgr = false // svg per react
54
61
  ,svgoConfig = useSvgo? (await import('./webpack-config-modules/svgo.config.mjs')).default : null
@@ -57,7 +64,8 @@ const isDevelopment = process.env.NODE_ENV === 'development'
57
64
  // dir di output: relativa a QUESTO file ('../build' se il frontend è in una
58
65
  // sottodirectory, './build' se webpack.config.mjs è nella root del progetto)
59
66
  ,output_dir = path.resolve(__dirname, './build')
60
- // ,output_dir = isDevelopment? '_dev' : 'build' // symfony
67
+ // SETUP symfony
68
+ // ,output_dir = isDevelopment? '_dev' : 'build'
61
69
 
62
70
  // dir delle favicons generate da `npx create-favicons` (vedi package.json):
63
71
  // il path assoluto serve a CopyWebpackPlugin/HtmlWebpackPlugin (i path
@@ -66,8 +74,8 @@ const isDevelopment = process.env.NODE_ENV === 'development'
66
74
  ,favicons_path = path.resolve(__dirname, './app/favicons/output') // commentare se non usato
67
75
  ,favicons_path_regexp = /favicons\/output/ // source pattern per le favicons (regexp o null)
68
76
 
69
- //sf:
70
- //,favicons_path
77
+ // SETUP symfony
78
+ // // ,favicons_path = path.resolve(__dirname, './app/favicons/output') // commentare se non usato
71
79
  // ,favicons_path_regexp = null
72
80
 
73
81
 
@@ -98,6 +106,29 @@ const isDevelopment = process.env.NODE_ENV === 'development'
98
106
  // (copiato da minimo da starter-install.sh, generato da `npm run 'build tokens'`)
99
107
  ,customPropsFile = path.resolve(__dirname, './app/css/custom-properties.css')
100
108
 
109
+ /*
110
+ chunk `shared` (splitChunks + runtimeChunk 'single'): true = js e css comuni
111
+ in `shared.js` / `shared.css` + `runtime.js` (vedi `shared_chunk_paths`);
112
+ false = nessun chunk condiviso, utile nei progetti con una sola pagina (più al
113
+ massimo una pagina di errore): la entry principale (`mainEntry`) è sempre
114
+ caricata e contiene da sola tutto il js/css comune e le definizioni delle
115
+ custom properties per tutti i css.
116
+ NB: con `false` i template NON devono più linkare shared.js, shared.css e
117
+ runtime.js (vedi _sf/templates/_main-tpl.html.twig e la pagina di errore)
118
+ */
119
+ ,useSharedChunk = true
120
+ /*
121
+ entry principale, sempre caricata: con `useSharedChunk: false` riceve le
122
+ definizioni delle custom properties per tutti i css delle altre entry
123
+ */
124
+ ,mainEntry = 'index'
125
+ /*
126
+ solo con `useSharedChunk: false`: entry NON `.critical` che non caricano il css
127
+ di `mainEntry`. Restano fuori dal set principale del plugin custom properties
128
+ e ricevono un set proprio, con le proprie definizioni (default: [])
129
+ */
130
+ ,standaloneEntries = []
131
+
101
132
  // PurgeCSS e plugin custom properties lavorano sugli asset css finali:
102
133
  // in dev, con `false`, sono entrambi disattivati (build più veloce, css
103
134
  // iniettato con style-loader; se `useCustomPropsPlugin` è true le definizioni
@@ -106,8 +137,6 @@ const isDevelopment = process.env.NODE_ENV === 'development'
106
137
  // rispettivi flag `usePurgeCss` / `useCustomPropsPlugin`) e `inlineCssInDevMode`
107
138
  // viene forzato a false
108
139
  ,purgeCssInDev = false
109
- ,inlineCssInDev = inlineCssInDevMode && !purgeCssInDev // valore effettivo passato a cssRules
110
- ,runPurgeCss = usePurgeCss && (!isDevelopment || purgeCssInDev)
111
140
  ,runCustomPropsPlugin = useCustomPropsPlugin && (!isDevelopment || purgeCssInDev)
112
141
  // ,manifest_shared_seed = {}
113
142
  ;
@@ -116,6 +145,7 @@ const { CustomPropsPurgeCssPlugin } = runCustomPropsPlugin
116
145
  ? await import('./webpack-config-modules/custom-props-purgecss-plugin.mjs')
117
146
  : {};
118
147
 
148
+ // (solo con `useSharedChunk: true`, vedi sopra)
119
149
  // cacheGroup `shared` (splitChunks): raccoglie in `shared.js` / `shared.css` i
120
150
  // moduli js e css provenienti da node_modules e dalle directory condivise del
121
151
  // progetto (vedi `pathsRegexp` sotto), così non vengono duplicati in ogni entry.
@@ -217,6 +247,8 @@ const CopyWebpackPluginPatterns = [
217
247
  const projectEntries = {
218
248
  'index': './app/index.js',
219
249
 
250
+ 'error-pages': './app/error-pages/error-pages.js',
251
+
220
252
  // css critici da includere inline nei template html: il suffisso `.critical` nel nome
221
253
  // della entry attiva l'istanza PurgeCSS dedicata con purge stretto
222
254
  // (vedi purgecss-setup.mjs) e la regola dedicata in css-rules.mjs
@@ -237,6 +269,41 @@ const entries = (useCustomPropsPlugin && isDevelopment && !purgeCssInDev)
237
269
  : projectEntries;
238
270
 
239
271
 
272
+ // regexp per gli asset css compilati di una entry: corrisponde a `nome.css` (dev con
273
+ // WEBPACK_SERVE, senza hash) e a `nome.<hash>.css`, ma NON a `nome.critical.<hash>.css`
274
+ // (il wildcard `*` di una stringa, invece, non corrisponde a `nome.css` e corrisponde
275
+ // anche a `nome.critical.<hash>.css`)
276
+ const cssAssetRegexp = (entryName) =>
277
+ new RegExp(`^${entryName.replace(/[.+?^${}()|[\]\\]/g, '\\$&')}(\\.[^./]+)?\\.css$`);
278
+
279
+ // set del CustomPropsPurgeCssPlugin (vedi `sets` nei `plugins`). L'elenco delle entry
280
+ // css è derivato da `projectEntries`: aggiungere una entry lì è sufficiente
281
+ const cssEntries = Object.keys(projectEntries).filter(name => !/\.critical/.test(name))
282
+ ,criticalEntries = Object.keys(projectEntries).filter(name => /\.critical/.test(name))
283
+ ,customPropsSets = [
284
+
285
+ // i critical css sono inline nei template: restano autosufficienti
286
+ ...criticalEntries.map(name => ({ sources: [cssAssetRegexp(name)] })),
287
+
288
+ ...(useSharedChunk
289
+ // shared.css è linkato in tutte le pagine: contiene le definizioni per tutti i
290
+ // css delle entry (le definizioni non sono duplicate negli altri asset)
291
+ ? [{
292
+ sources: [cssAssetRegexp('shared'), ...cssEntries.map(cssAssetRegexp)],
293
+ target: cssAssetRegexp('shared')
294
+ }]
295
+ // senza shared: le definizioni sono iniettate solo nel css di `mainEntry`
296
+ // (sempre caricato); le entry che non lo caricano hanno un set proprio
297
+ : [
298
+ {
299
+ sources: cssEntries.filter(name => !standaloneEntries.includes(name)).map(cssAssetRegexp),
300
+ target: cssAssetRegexp(mainEntry)
301
+ },
302
+ ...standaloneEntries.map(name => ({ sources: [cssAssetRegexp(name)] }))
303
+ ]
304
+ )
305
+ ];
306
+
240
307
  const config = {
241
308
  mode: isDevelopment ? 'development' : 'production',
242
309
 
@@ -272,7 +339,7 @@ const config = {
272
339
  clean: !isDevelopment
273
340
  },
274
341
 
275
- /* SYMFONY:
342
+ /* SETUP symfony
276
343
  output: {
277
344
  path: path.resolve(__dirname, `./public/${output_dir}` ),
278
345
  // filename: '[name].js',
@@ -302,20 +369,25 @@ const config = {
302
369
  extractComments: false
303
370
  })
304
371
  ],
305
- runtimeChunk: 'single', // true
306
- splitChunks: {
307
- cacheGroups: {
308
-
309
- shared: {
310
- // vedi shared_chunk_paths sopra per la logica completa del test
311
- test: shared_chunk_paths,
312
- name: 'shared',
313
- enforce: true,
314
- // le entry `.critical` restano autosufficienti (css inline nei template)
315
- chunks: (chunk) => !/\.critical/.test(chunk.name)
316
- }
372
+ // chunk `shared` e runtime: solo con `useSharedChunk: true`
373
+ ...(useSharedChunk
374
+ ? {
375
+ runtimeChunk: 'single', // true
376
+ splitChunks: {
377
+ cacheGroups: {
378
+
379
+ shared: {
380
+ // vedi shared_chunk_paths sopra per la logica completa del test
381
+ test: shared_chunk_paths,
382
+ name: 'shared',
383
+ enforce: true,
384
+ // le entry `.critical` restano autosufficienti (css inline nei template)
385
+ chunks: (chunk) => !/\.critical/.test(chunk.name)
386
+ }
387
+ }
388
+ },
317
389
  }
318
- },
390
+ : {})
319
391
  },
320
392
 
321
393
  // =>> performance
@@ -339,6 +411,7 @@ const config = {
339
411
  client: { overlay: true, },
340
412
  },
341
413
 
414
+ // SETUP symfony
342
415
  // =>> devServer (con symfony)
343
416
  // reverse proxy davanti a `symfony serve` (porta 8102, vedi package.json):
344
417
  // il browser va aperto su questo dev server (non su :8102). Le richieste per
@@ -358,7 +431,10 @@ const config = {
358
431
  // // di servire una versione stale in cache su reload manuale
359
432
  // headers: { 'Cache-Control': 'no-store' },
360
433
  // hot: true,
361
- // open: { app: { name: 'Google Chrome' } }, // apertura automatica del browser all'avvio
434
+ // open: {
435
+ // app: { name: 'Google Chrome' }, // apertura automatica del browser all'avvio
436
+ // // target: ['page1', 'page2'], // pafine da aprire all'avvio
437
+ // },
362
438
  // static: false, // niente static serving proprio: tutto il resto passa dal proxy verso Symfony
363
439
  // devMiddleware: { writeToDisk: true, },
364
440
  // client: { overlay: true, },
@@ -405,26 +481,20 @@ const config = {
405
481
  : []
406
482
  ),
407
483
 
484
+ // SETUP symfony (decommentare)
408
485
  // =>> plugins: WebpackManifestPlugin
409
486
  // new WebpackManifestPlugin({
410
- // fileName: path.join(output_dir, 'manifest.json'),
411
- // sf: fileName: 'manifest.json', // scrive in output.path
487
+ // fileName: path.join(output_dir, 'manifest.json'), // NB: symfony -> fileName: 'manifest.json', // scrive in output.path
412
488
  // // basePath: item.source_dirname
413
489
  // // removeKeyHash: /\?.*$/, // /([a-f0-9]{32}\.?)/gi, // /(\?as_asset)$/,
414
- // // rimuove i font dal manifest. Non necessari, rendono il file inutilmente grande
490
+ // // rimuove dal manifest i font non woff2 (non necessari, rendono il file inutilmente grande);
491
+ // // i woff2 restano per consentire il preload con asset() nei template sf
415
492
  // filter: isDevelopment? undefined : (FileDescriptor) => {
416
- // return /fonts/.test(FileDescriptor.path)? false : true;
493
+ // return !/fonts/.test(FileDescriptor.path) || /\.woff2$/.test(FileDescriptor.path);
417
494
  // },
418
495
  // sort: isDevelopment? undefined : (a, b) => a.name.localeCompare(b.name)
419
496
  // }),
420
497
 
421
- // =>> plugins: MiniCssExtractPlugin
422
- new MiniCssExtractPlugin({
423
- filename: '[name].[contenthash].css',
424
- chunkFilename: '[id].[contenthash].css',
425
- ignoreOrder: true
426
- }),
427
-
428
498
  // =>> plugins: MiniCssExtractPlugin
429
499
  // contenthash solo se non si usa Dev Server
430
500
  new MiniCssExtractPlugin({
@@ -440,6 +510,7 @@ const config = {
440
510
  // : [new InlineCriticalCssPlugin({ match: (href) => href?.includes('.critical') })]
441
511
  // ),
442
512
 
513
+ // SETUP symfony (rimuovere)
443
514
  // =>> plugins: HtmlWebpackPlugin (manifest)
444
515
  new HtmlWebpackPlugin({
445
516
  filename: 'manifest.webmanifest',
@@ -448,6 +519,7 @@ const config = {
448
519
  minify: false //!isDevelopment
449
520
  }),
450
521
 
522
+ // SETUP symfony (rimuovere)
451
523
  // =>> plugins: HtmlWebpackPlugin
452
524
  new HtmlWebpackPlugin({
453
525
  filename: 'index.html',
@@ -458,6 +530,7 @@ const config = {
458
530
  // base: isDevelopment ? '/' : '/xxxxx/',
459
531
  }),
460
532
 
533
+ // SETUP symfony (rimuovere)
461
534
  // =>> plugins: HtmlWebpackInjectAttributesPlugin
462
535
  // new HtmlWebpackInjectAttributesPlugin({
463
536
  // // La funzione riceve un oggetto con gli attributi del tag corrente
@@ -471,6 +544,8 @@ const config = {
471
544
  // }
472
545
  // }),
473
546
 
547
+
548
+ // SETUP symfony (rimuovere)
474
549
  // =>> plugins: HtmlWebpackInjectPreload
475
550
  // https://github.com/principalstudio/html-webpack-inject-preload
476
551
  ...(isDevelopment
@@ -515,8 +590,8 @@ const config = {
515
590
 
516
591
  },
517
592
  raw: true,
518
- // niente banner nei critical css: vengono inseriti inline nei template html
519
- exclude: /\.critical/ // chunk name
593
+ // niente banner nei critical css ( vengono inseriti inline nei template html), nelle immagini e nei font
594
+ exclude: /\.critical|\.(svg|png|jpe?g|gif|webp|avif|ico|woff2?|eot|ttf|otf)$/i
520
595
  }),
521
596
 
522
597
  // =>> plugins: PurgeCSSPlugin (solo classi/keyframes, le custom properties sono
@@ -531,7 +606,7 @@ const config = {
531
606
  // watch mode i template twig NON sono osservati da webpack: dopo aver
532
607
  // aggiunto una classe solo in un twig occorre rilanciare la build (o toccare
533
608
  // un file js/css) per aggiornare il purge
534
- ...(runPurgeCss
609
+ ...(usePurgeCss && (!isDevelopment || purgeCssInDev)
535
610
  ? createPurgeCSSPlugins({
536
611
 
537
612
  // SOLO file che generano markup o classi (twig, php, js);
@@ -591,27 +666,25 @@ const config = {
591
666
  definitionsFile: customPropsFile,
592
667
 
593
668
  // set di asset css elaborati in modo indipendente: `sources` sono i nomi
594
- // degli asset compilati (con l'hash nel nome: usare `*`, oppure una
595
- // RegExp), `target` l'asset in cui iniettare le definizioni (se omesso
596
- // è il primo asset del set; se non corrisponde ad alcun asset e non ha
597
- // `*` viene emesso come nuovo asset, che va poi linkato nei template).
598
- // NB: `*` corrisponde a qualsiasi carattere: 'layout.*.css' corrisponde
599
- // anche a 'layout.critical.<hash>.css'
600
- sets: [
601
- // il critical css è inline nei template: deve restare autosufficiente
602
- { sources: ['layout.critical.*.css'] },
603
-
604
- // shared.css è linkato in tutte le pagine: contiene le definizioni
605
- // per tutti i css delle entry (le definizioni non sono duplicate
606
- // negli altri asset). Ogni css delle entry va elencato qui
607
- { sources: ['shared.*.css', 'index.*.css'], target: 'shared.*.css' },
608
- ],
609
-
610
- // css usati fuori dagli asset purgati (shadow DOM dei web components,
611
- // import `?raw`): tutti i loro usi di var() contano per tutti i set
669
+ // degli asset compilati (con l'hash nel nome: usare una RegExp, vedi
670
+ // `cssAssetRegexp`), `target` l'asset in cui iniettare le definizioni (se
671
+ // omesso è il primo asset del set; se non corrisponde ad alcun asset e non
672
+ // è una stringa senza `*` non viene emesso nulla).
673
+ // NB: evitare i wildcard `*`: 'index.*.css' non corrisponde a 'index.css'
674
+ // (dev con WEBPACK_SERVE) e corrisponde invece a 'index.critical.<hash>.css'.
675
+ // I set sono costruiti in `customPropsSets` (sopra) a partire da
676
+ // `projectEntries`, in base a `useSharedChunk`: aggiungendo una entry
677
+ // non serve modificare nulla qui
678
+ sets: customPropsSets,
679
+
680
+ // css usati fuori dal bundle: tutti i loro usi di var() contano per tutti i
681
+ // set. I css importati con `?raw` (shadow DOM dei web components) sono
682
+ // rilevati automaticamente nei js dei chunk, solo per i componenti
683
+ // realmente importati: un glob largo qui porterebbe nel css anche le
684
+ // props di componenti non importati
612
685
  extraUsageGlobs: [
613
- path.resolve(__dirname, './app/src/web-components/**/*.css'),
614
- `${minimo_path}/src/web-components/**/*.css`,
686
+ // path.resolve(__dirname, './app/src/web-components/**/*.css'),
687
+ // `${minimo_path}/src/web-components/**/*.css`,
615
688
  ],
616
689
 
617
690
  // props da includere comunque in tutti i set (nomi esatti o RegExp),
@@ -708,7 +781,12 @@ const config = {
708
781
  },
709
782
 
710
783
  // =>> rules: svg
711
- ...svgRules({useSvgo: useSvgo, svgoConfig: svgoConfig, useSvgr: useSvgr, favicons_path_regexp: favicons_path_regexp?? null }),
784
+ ...svgRules({
785
+ useSvgo: useSvgo,
786
+ svgoConfig: svgoConfig,
787
+ useSvgr: useSvgr,
788
+ favicons_path_regexp: favicons_path_regexp?? null
789
+ }),
712
790
 
713
791
  // =>> rules: Images / pdf
714
792
  {
@@ -771,7 +849,12 @@ const config = {
771
849
  },
772
850
 
773
851
  // =>> rules: css / scss
774
- ...cssRules({isDevelopment: isDevelopment, useSass: useSass, inlineCssInDevMode: inlineCssInDev, postcssConfig_path: postcssConfig_path})
852
+ ...cssRules({
853
+ isDevelopment: isDevelopment,
854
+ useSass: useSass,
855
+ inlineCssInDevMode: inlineCssInDevMode && !purgeCssInDev,
856
+ postcssConfig_path: postcssConfig_path
857
+ })
775
858
  ] // end rules
776
859
  }, // end module
777
860
 
@@ -198,8 +198,10 @@ force_cat() {
198
198
  # sotto-cartelle così com'è in source_files: aggiungere, spostare o rinominare
199
199
  # file lì non richiede modifiche a questo script.
200
200
  # Il terzo argomento (opzionale) è il nome di una funzione di rename invocata
201
- # su ogni singolo basename, per i casi in cui il nome del file sorgente non
202
- # coincide con quello di destinazione (vedi rename_root_file).
201
+ # solo sui file posti direttamente nella root di src_root (non su quelli nelle
202
+ # sotto-cartelle, i cui nomi restano invariati: es. _sf/templates/_main-tpl.html.twig,
203
+ # referenziato così da home.html.twig), per i casi in cui il nome del file
204
+ # sorgente non coincide con quello di destinazione (vedi rename_root_file).
203
205
  # Il quarto argomento (opzionale, default: safe_cat_with_ports) è la funzione
204
206
  # di copia da usare per ogni file: safe_cat_with_ports confronta e backuppa
205
207
  # il singolo file (sostituzione porte no-op se non contiene placeholder);
@@ -210,6 +212,9 @@ force_cat() {
210
212
  # dell'installazione dei pacchetti npm (vedi più sotto).
211
213
  # I file .DS_Store (macOS) vengono sempre ignorati: sono binari e farebbero
212
214
  # fallire il sed di safe_cat_with_ports ("illegal byte sequence").
215
+ # I file .gitkeep non vengono copiati, ma la cartella che li contiene viene
216
+ # comunque creata nella destinazione (servono solo a mantenere la cartella nel
217
+ # repo di minimo).
213
218
  install_tree() {
214
219
  local src_root="$1"
215
220
  local dest_root="$2"
@@ -221,10 +226,14 @@ install_tree() {
221
226
  rel="${file#"$src_root"/}"
222
227
  dir="$(dirname "$rel")"
223
228
  base="$(basename "$rel")"
229
+ if [ "$base" = ".gitkeep" ]; then
230
+ [ "$dir" = "." ] || mkdir -p "${dest_root}/${dir}"
231
+ continue
232
+ fi
224
233
  if [ -n "$exclude" ] && [[ " $exclude " == *" $base "* ]]; then
225
234
  continue
226
235
  fi
227
- if [ -n "$rename_fn" ]; then
236
+ if [ -n "$rename_fn" ] && [ "$dir" = "." ]; then
228
237
  new_base="$("$rename_fn" "$base")"
229
238
  else
230
239
  new_base="$base"
@@ -239,7 +248,8 @@ install_tree() {
239
248
  done < <(find "$src_root" -type f ! -name .DS_Store)
240
249
  }
241
250
 
242
- # Rename applicato ai file di source_files/root/ in fase di copia:
251
+ # Rename applicato ai soli file posti direttamente in source_files/root/ (non alle
252
+ # sotto-cartelle) in fase di copia:
243
253
  # - prefisso singolo underscore -> dotfile (es. _gitignore -> .gitignore);
244
254
  # il doppio underscore (__project__.code-workspace) non viene toccato,
245
255
  # il nome resta invariato
@@ -50,14 +50,12 @@ Non servono nuovi pacchetti npm: il plugin usa `postcss` e `glob`, già presenti
50
50
  }
51
51
  ```
52
52
 
53
- 3. **Aggiungere** i nuovi flag e le costanti derivate (dopo `purgeCSSOptions`):
53
+ 3. **Aggiungere** i nuovi flag e la costante derivata (dopo `purgeCSSOptions`):
54
54
 
55
55
  ```js
56
56
  ,useCustomPropsPlugin = true // false: il plugin non viene caricato, le custom properties restano a carico del progetto
57
57
  ,customPropsFile = path.resolve(__dirname, './app/css/custom-properties.css')
58
58
  ,purgeCssInDev = false // true (solo per test): purge e plugin attivi anche in dev
59
- ,inlineCssInDev = inlineCssInDevMode && !purgeCssInDev
60
- ,runPurgeCss = usePurgeCss && (!isDevelopment || purgeCssInDev)
61
59
  ,runCustomPropsPlugin = useCustomPropsPlugin && (!isDevelopment || purgeCssInDev)
62
60
  ```
63
61
 
@@ -81,7 +79,7 @@ Non servono nuovi pacchetti npm: il plugin usa `postcss` e `glob`, già presenti
81
79
  ```
82
80
 
83
81
  6. **`optimization`**: sostituire il commento `// realContentHash: true,` con `realContentHash: !isDevelopment || purgeCssInDev,`.
84
- 7. **PurgeCSS**: la condizione `...(usePurgeCss ? createPurgeCSSPlugins({...}) : [])` diventa `...(runPurgeCss ? ... : [])`, e nella chiamata a `createPurgeCSSPlugins` va **rimosso** il blocco `variablesSafelist: { declarationGlobs, shadowGlobs, seeds }`. I glob `shadowGlobs` e `seeds` si spostano nel plugin (punto seguente, come `extraUsageGlobs` e `seeds`).
82
+ 7. **PurgeCSS**: la condizione `...(usePurgeCss ? createPurgeCSSPlugins({...}) : [])` diventa `...(usePurgeCss && (!isDevelopment || purgeCssInDev) ? ... : [])`, e nella chiamata a `createPurgeCSSPlugins` va **rimosso** il blocco `variablesSafelist: { declarationGlobs, shadowGlobs, seeds }`. I glob `shadowGlobs` e `seeds` si spostano nel plugin (punto seguente, come `extraUsageGlobs` e `seeds`).
85
83
  8. **Chunk `shared` anche per i css** (in v2 i css restavano nel css di ogni entry, duplicati). Nel commento e nella funzione `shared_chunk_paths` **rimuovere** la riga `if (module.type === 'css/mini-extract') return false;` (e il vecchio commento/`TODO` che spiegava perché i css restavano fuori dallo `shared`), e nel cacheGroup `shared` (`optimization.splitChunks.cacheGroups`) sostituire `chunks: 'all'` con:
86
84
 
87
85
  ```js
@@ -113,7 +111,7 @@ Non servono nuovi pacchetti npm: il plugin usa `postcss` e `glob`, già presenti
113
111
  ```
114
112
 
115
113
  I `sets` vanno adattati alle entry del progetto: `sources` è l'elenco dei nomi degli asset CSS compilati (con l'hash nel nome, si usa `*`, oppure una RegExp) e `target` (opzionale) l'asset in cui iniettare le definizioni; se omesso è il primo asset del set. Ogni entry con un proprio css deve comparire in un set, altrimenti l'uso di custom properties in quel css non viene rilevato e le definizioni corrispondenti mancano.
116
- 10. **`cssRules`**: passare `inlineCssInDevMode: inlineCssInDev` (non più `inlineCssInDevMode`).
114
+ 10. **`cssRules`**: passare `inlineCssInDevMode: inlineCssInDevMode && !purgeCssInDev` (non più `inlineCssInDevMode`).
117
115
  11. Aggiornare, se presenti, i commenti che citano `variables: true`, `safelist.variables` o `purgecss-variables-safelist.mjs`.
118
116
 
119
117
  ### 3. Template
@@ -149,3 +147,99 @@ Con `HtmlWebpackPlugin` (`inject`) `shared.css` è inserito automaticamente. Se
149
147
  3. In `build/` esiste `shared.<hash>.css` (con le definizioni delle custom properties), le pagine lo linkano prima del css della entry senza 404, i css delle entry non duplicano gli stili condivisi e la entry `.critical` resta autosufficiente.
150
148
  4. `NODE_ENV=development` (con `webpack serve`): le pagine mostrano stili e colori corretti; il master viene caricato per intero come primo modulo delle entry.
151
149
  5. Se qualche componente perde stili solo in produzione, provare `useCustomPropsPlugin = false` per isolare il problema.
150
+
151
+
152
+ ## Da v3 a v3.1
153
+
154
+ Novità della v3.1: il chunk `shared` diventa opzionale (`useSharedChunk`), i `sets` del plugin custom properties sono derivati da `projectEntries` e usano regexp al posto dei wildcard, e il plugin rileva le custom properties dei css `?raw` (web components) nei js dei chunk, per cui `extraUsageGlobs` non serve più per i web components.
155
+
156
+ Riepilogo delle modifiche:
157
+
158
+ | Cosa | Dove |
159
+ |---|---|
160
+ | Flag `useSharedChunk` (chunk `shared` opzionale), `mainEntry`, `standaloneEntries` | `webpack.config.mjs` |
161
+ | `sets` derivati da `projectEntries`, con regexp (`cssAssetRegexp`) al posto dei wildcard | `webpack.config.mjs` |
162
+ | Scansione dei js dei chunk per i css `?raw`; `extraUsageGlobs: []` | `custom-props-purgecss-plugin.mjs`, `webpack.config.mjs` |
163
+ | Riferimenti a `shared.*` / `runtime.js` commentati come opzionali | `_sf/templates/_main-tpl.html.twig`, pagina di errore e template del progetto |
164
+ | `MiniCssExtractPlugin` presente una sola volta; entry `error-pages`; commenti `NB symfony` | `webpack.config.mjs` |
165
+
166
+ ### 1. Moduli in `webpack-config-modules/`
167
+
168
+ - **Sostituire** `custom-props-purgecss-plugin.mjs` con la versione v3.1 (`// v.3.1`). Gli altri moduli non cambiano.
169
+
170
+ ### 2. Modifiche a `webpack.config.mjs`
171
+
172
+ 1. Riga 2: `// v.3` → `// v.3.1`.
173
+ 2. **Aggiungere** i flag tra le costanti di configurazione (dopo `customPropsFile`):
174
+
175
+ ```js
176
+ ,useSharedChunk = true // false: nessun chunk shared né runtime, per progetti con una sola pagina (più al massimo una pagina di errore)
177
+ ,mainEntry = 'index' // entry sempre caricata: con useSharedChunk false riceve le definizioni delle custom properties
178
+ ,standaloneEntries = [] // con useSharedChunk false: entry non `.critical` che non caricano il css di mainEntry (set proprio)
179
+ ```
180
+
181
+ 3. **`optimization`**: rendere condizionali `runtimeChunk: 'single'` e `splitChunks.cacheGroups.shared`:
182
+
183
+ ```js
184
+ optimization: {
185
+ // ...
186
+ ...(useSharedChunk
187
+ ? {
188
+ runtimeChunk: 'single',
189
+ splitChunks: { cacheGroups: { shared: { /* come in v3 */ } } }
190
+ }
191
+ : {})
192
+ },
193
+ ```
194
+
195
+ 4. **Sets del plugin**: prima di `const config`, definire l'helper `cssAssetRegexp` e i set `customPropsSets`, derivati da `projectEntries` (aggiungendo una entry non serve modificare altro):
196
+
197
+ ```js
198
+ // corrisponde a `nome.css` (dev con WEBPACK_SERVE) e `nome.<hash>.css`, NON a `nome.critical.<hash>.css`
199
+ const cssAssetRegexp = (entryName) =>
200
+ new RegExp(`^${entryName.replace(/[.+?^${}()|[\]\\]/g, '\\$&')}(\\.[^./]+)?\\.css$`);
201
+
202
+ const cssEntries = Object.keys(projectEntries).filter(name => !/\.critical/.test(name))
203
+ ,criticalEntries = Object.keys(projectEntries).filter(name => /\.critical/.test(name))
204
+ ,customPropsSets = [
205
+ // i critical css sono inline nei template: restano autosufficienti
206
+ ...criticalEntries.map(name => ({ sources: [cssAssetRegexp(name)] })),
207
+ ...(useSharedChunk
208
+ // shared.css è linkato in tutte le pagine e contiene le definizioni per tutti i css delle entry
209
+ ? [{
210
+ sources: [cssAssetRegexp('shared'), ...cssEntries.map(cssAssetRegexp)],
211
+ target: cssAssetRegexp('shared')
212
+ }]
213
+ // senza shared: definizioni solo nel css di `mainEntry`; le entry che non lo caricano hanno un set proprio
214
+ : [
215
+ {
216
+ sources: cssEntries.filter(name => !standaloneEntries.includes(name)).map(cssAssetRegexp),
217
+ target: cssAssetRegexp(mainEntry)
218
+ },
219
+ ...standaloneEntries.map(name => ({ sources: [cssAssetRegexp(name)] }))
220
+ ]
221
+ )
222
+ ];
223
+ ```
224
+
225
+ Nel plugin sostituire i `sets` con `sets: customPropsSets`. Si usano RegExp e non i wildcard `*`: `'index.*.css'` non corrisponde a `index.css` (dev con `WEBPACK_SERVE`) e corrisponde invece a `index.critical.<hash>.css`.
226
+ 5. **`extraUsageGlobs`**: sostituire i glob dei web components con `extraUsageGlobs: []` (i glob precedenti possono restare commentati). `minimo_path` resta, perché è usato anche nei `contentGlobs` di PurgeCSS.
227
+
228
+ 6. **`MiniCssExtractPlugin`**: nell'array `plugins` deve comparire **una sola volta**. Se il config ne contiene due, eliminare quello con `filename: '[name].[contenthash].css'` e tenere quello con la logica `process.env.WEBPACK_SERVE ? '[name].css' : '[name].[contenthash].css'` (e il corrispondente `chunkFilename`).
229
+ 7. **Entry `error-pages`**: nel template di base `projectEntries` include `'error-pages': './app/error-pages/error-pages.js'` (pagina di errore, che carica anche il css di `index`). Nei progetti con pagina di errore va aggiunta; non serve altro per i `sets`, perché derivano da `projectEntries`.
230
+ 8. **Commenti `NB symfony`** (facoltativo, solo leggibilità): le indicazioni per Symfony (`sf:`, `SYMFONY:`) sono state uniformate in commenti `NB symfony` che dicono cosa commentare, decommentare o rimuovere (import di `HtmlWebpackPlugin` / `HtmlWebpackInjectPreload`, `apiPort`, `output_dir`, `WebpackManifestPlugin`, plugin html). `apiPort` nel template è ora commentato. Nessuna modifica di comportamento.
231
+
232
+ ### 3. Template
233
+
234
+ Con `useSharedChunk = false` i template **non** devono referenziare `shared.css`, `shared.js` e `runtime.js` (preload, link e script): nei template di esempio (`_main-tpl.html.twig` e pagina di errore) un commento Twig indica le righe da rimuovere. Le definizioni delle custom properties sono nel css di `mainEntry`, che deve essere linkato in ogni pagina; le entry elencate in `standaloneEntries` hanno invece le proprie definizioni nel loro css. Con `useSharedChunk = true` i template restano invariati.
235
+
236
+ ### 4. Cambiamenti di comportamento
237
+
238
+ - **Scansione dei js:** per ogni set il plugin analizza, oltre ai css, i js dei chunk che li contengono (e dei chunk da essi raggiunti). I css importati con `?raw` (shadow DOM dei web components) sono stringhe nel bundle: le loro props entrano nel css solo per i componenti realmente importati. `extraUsageGlobs` va quindi lasciato vuoto salvo css caricati fuori dal bundle: un glob largo (es. `src/web-components/**/*.css` di minimo) porta nel css anche le props di componenti non importati. Una entry solo js, senza css nei `sources`, non viene scansionata.
239
+ - Anche gli usi di `var(--…)` presenti nei js (es. stili generati a runtime) contano come usati.
240
+
241
+ ### 5. Verifica dopo l'aggiornamento
242
+
243
+ 1. `NODE_ENV=production npx webpack --config ./webpack.config.mjs --stats minimal`: nessun errore o warning del plugin.
244
+ 2. Nel css con le definizioni non compaiono props di web components non importati (es. `--jt-*`, `--sdt-*`); per un componente importato con `?raw` le sue props sono presenti.
245
+ 3. Con `useSharedChunk = false`: in `build/` non esistono `shared.*` né `runtime.*` e le definizioni sono nel solo css di `mainEntry`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.40.0",
3
+ "version": "1.40.2",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -32,11 +32,12 @@ custom propeties:
32
32
 
33
33
  /* stylelint-disable declaration-no-important */
34
34
 
35
- html, body {
36
- height: 100%;
37
- padding: 0;
38
- margin: 0;
39
-
35
+ html.uspg {
36
+ &, & body {
37
+ height: 100%;
38
+ padding: 0;
39
+ margin: 0;
40
+ }
40
41
  }
41
42
 
42
43
  *, *::before, *::after {
package/src/minimo.css CHANGED
@@ -1,9 +1,9 @@
1
1
  /* decomment if you want to use layers. see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer */
2
2
  /* @layer reset, base, components, utilities, project, overrides; */
3
3
 
4
- /* @import '@css/fonts.css'; */
4
+ @import '@css/fonts.css';
5
5
  /* @import '@css/custom-media.css'; */ /* managed by postcss */
6
- /* @import '@css/custom-properties.css' layer('base'); */ /* managed by postcss-jit-props */
6
+ /* @import '@css/custom-properties.css'; */ /* layer('base'); */ /* comment if managed by postcss-jit-props */
7
7
 
8
8
  @import '@minimoSrc/css/reset.css';
9
9
  @import '@minimoSrc/css/layout-base.css';
@@ -41,6 +41,8 @@ const PARTICLE_CASING_MAP = new Map(PARTICELLE.map(term => [term.toLowerCase(),
41
41
  * Improves a text string by fixing punctuation spacing, multiple spaces,
42
42
  * typographic quotes, non-breaking spaces after Italian particles/articles,
43
43
  * and optionally enforcing the exact casing of custom words.
44
+ * Particles are forced to their listed casing, except at the start of the text
45
+ * where their first letter is capitalized.
44
46
  *
45
47
  * @param {string} str - input string to process
46
48
  * @param {string[]} [custom_words] - list of words whose exact casing must be preserved (e.g. `['iPhone', 'macOS']`) (default: [])
@@ -75,8 +77,14 @@ export function betterText(str, custom_words = []) {
75
77
  return match.replace(/ +/g, '\u00A0');
76
78
  });
77
79
 
78
- // enforce exact casing of every particle in a single pass
79
- str = str.replace(PARTICLE_CASING_REGEX, match => PARTICLE_CASING_MAP.get(match.toLowerCase()) ?? match);
80
+ // enforce exact casing of every particle in a single pass;
81
+ // a particle at the very start of the text (optionally after an opening quote) is capitalized
82
+ str = str.replace(PARTICLE_CASING_REGEX, (match, _p1, offset, whole) => {
83
+ const exact = PARTICLE_CASING_MAP.get(match.toLowerCase()) ?? match;
84
+ return /^[“‘]?$/.test(whole.slice(0, offset))
85
+ ? exact.charAt(0).toUpperCase() + exact.slice(1)
86
+ : exact;
87
+ });
80
88
 
81
89
  if(custom_words.length) {
82
90
  custom_words.forEach(item => {