@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.
- package/dev-tools/create-favicons/src/default-params.mjs +5 -5
- package/dev-tools/design-tokens-builder/tokens-config-sample.mjs +1 -1
- package/dev-tools/starter-kit/source_files/app/css/fonts.css +2 -2
- package/dev-tools/starter-kit/source_files/root/_gitignore +1 -0
- package/dev-tools/starter-kit/source_files/root/_sf/controller/UnsplashController.php +2 -1
- package/dev-tools/starter-kit/source_files/root/_sf/templates/_main-tpl.html.twig +9 -2
- package/dev-tools/starter-kit/source_files/root/_sf/templates/bundles/TwigBundle/Exception/error.html.twig +5 -1
- package/dev-tools/starter-kit/source_files/root/_sf/templates/home.html.twig +17 -0
- package/dev-tools/starter-kit/source_files/root/package-tpl.json +1 -1
- package/dev-tools/starter-kit/source_files/root/webpack-config-modules/custom-props-purgecss-plugin.mjs +30 -6
- package/dev-tools/starter-kit/source_files/root/webpack.config.mjs +143 -60
- package/dev-tools/starter-kit/starter-install.sh +14 -4
- package/dev-tools/starter-kit/webpack-config-upg.md +99 -5
- package/package.json +1 -1
- package/src/components/unsplash-page/unsplash-page.module.css +6 -5
- package/src/minimo.css +2 -2
- package/src/utilities/better-text.js +10 -2
|
@@ -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: './
|
|
117
|
+
src: './design-tokens/*.{js,mjs,jsonc,json}',
|
|
118
118
|
prefix: 'my-project',
|
|
119
119
|
transform: { primary: 'primary.100' },
|
|
120
120
|
}
|
|
@@ -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 %} |
|
|
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
|
|
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
|
|
141
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
70
|
-
|
|
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
|
-
/*
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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: {
|
|
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
|
|
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
|
|
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
|
|
519
|
-
exclude: /\.critical
|
|
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
|
-
...(
|
|
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
|
|
595
|
-
//
|
|
596
|
-
// è il primo asset del set; se non corrisponde ad alcun asset e non
|
|
597
|
-
//
|
|
598
|
-
// NB:
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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({
|
|
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({
|
|
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
|
-
#
|
|
202
|
-
#
|
|
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
|
|
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
|
|
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 `...(
|
|
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:
|
|
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
|
@@ -32,11 +32,12 @@ custom propeties:
|
|
|
32
32
|
|
|
33
33
|
/* stylelint-disable declaration-no-important */
|
|
34
34
|
|
|
35
|
-
html
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 => {
|