@shopify/hydrogen 1.4.3 → 1.4.4
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/dist/esnext/foundation/Router/BrowserRouter.client.js +7 -1
- package/dist/esnext/framework/plugins/vite-plugin-css-rsc.d.ts +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-css-rsc.js +100 -3
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/plugins/vite-plugin-css-rsc.d.ts +1 -1
- package/dist/node/framework/plugins/vite-plugin-css-rsc.js +99 -2
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/package.json +2 -5
|
@@ -108,7 +108,13 @@ function useScrollRestoration({ location, pending, serverProps, scrollNeedsResto
|
|
|
108
108
|
}
|
|
109
109
|
// If there is a location hash, scroll to it
|
|
110
110
|
if (location.hash) {
|
|
111
|
-
|
|
111
|
+
let element;
|
|
112
|
+
try {
|
|
113
|
+
element = document.querySelector(location.hash);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// Do nothing, hash may not be a valid selector
|
|
117
|
+
}
|
|
112
118
|
if (element) {
|
|
113
119
|
element.scrollIntoView();
|
|
114
120
|
onFinishNavigating();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Plugin } from 'vite';
|
|
1
|
+
import { type Plugin } from 'vite';
|
|
2
2
|
export default function cssRsc(): Plugin;
|
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import MagicString from 'magic-string';
|
|
3
|
-
import { normalizePath } from 'vite';
|
|
3
|
+
import { normalizePath, } from 'vite';
|
|
4
4
|
const VITE_CSS_CHUNK_NAME = 'style.css';
|
|
5
5
|
const INJECT_STYLES_COMMENT = '<!--__INJECT_STYLES__-->';
|
|
6
|
+
const CSS_EXTENSIONS_RE = /\.(css|sass|scss|stylus|less)(\.|\?|$)/;
|
|
7
|
+
const CSS_MODULES_EXTENSIONS_RE = /\.module\.(css|sass|scss|stylus|less)(\?|$)/;
|
|
8
|
+
const EVENT_CSS_IMPORT = 'hydrogen-css-modules-update-imports';
|
|
9
|
+
const EVENT_CSS_CLASSES = 'hydrogen-css-modules-update-classes';
|
|
10
|
+
const CSS_MODULES_HMR_INJECT = `
|
|
11
|
+
import {createHotContext, injectQuery} from "/@vite/client";
|
|
12
|
+
|
|
13
|
+
if (!import.meta.hot) {
|
|
14
|
+
import.meta.hot = createHotContext("/index.html");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
import.meta.hot.on('${EVENT_CSS_IMPORT}', ({ids, timestamp}) => {
|
|
18
|
+
ids.forEach((id) => {
|
|
19
|
+
import(injectQuery(id, 't=' + timestamp));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
import.meta.hot.on('${EVENT_CSS_CLASSES}', ({replacements}) => {
|
|
24
|
+
replacements.forEach(([oldClass, newClass]) => {
|
|
25
|
+
document.querySelectorAll('.' + oldClass).forEach(node => {
|
|
26
|
+
node.classList.replace(oldClass, newClass);
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
`;
|
|
6
31
|
// Keep this in the outer scope to share it
|
|
7
32
|
// across client <> server builds.
|
|
8
33
|
let clientBuildPath;
|
|
@@ -16,6 +41,10 @@ let clientBuildPath;
|
|
|
16
41
|
*/
|
|
17
42
|
export default function cssRsc() {
|
|
18
43
|
let config;
|
|
44
|
+
let server;
|
|
45
|
+
let isUsingCssModules = false;
|
|
46
|
+
const hmrCssCopy = new Map();
|
|
47
|
+
const hmrCssQueue = new Set();
|
|
19
48
|
return {
|
|
20
49
|
name: 'hydrogen:css-rsc',
|
|
21
50
|
enforce: 'post',
|
|
@@ -27,6 +56,9 @@ export default function cssRsc() {
|
|
|
27
56
|
configResolved(_config) {
|
|
28
57
|
config = _config;
|
|
29
58
|
},
|
|
59
|
+
configureServer(_server) {
|
|
60
|
+
server = _server;
|
|
61
|
+
},
|
|
30
62
|
transform(code, id, options) {
|
|
31
63
|
if (options?.ssr && id.includes('index.html?raw')) {
|
|
32
64
|
// Mark the client build index.html to inject styles later
|
|
@@ -37,17 +69,63 @@ export default function cssRsc() {
|
|
|
37
69
|
map: s.generateMap({ file: id, source: id }),
|
|
38
70
|
};
|
|
39
71
|
}
|
|
72
|
+
// Manual HMR for CSS Modules
|
|
73
|
+
if (server && CSS_MODULES_EXTENSIONS_RE.test(id)) {
|
|
74
|
+
isUsingCssModules = true;
|
|
75
|
+
const file = id.split('?')[0];
|
|
76
|
+
// Note: this "CSS" file is actually JavaScript code.
|
|
77
|
+
// Get a copy of how this CSS was before the current update
|
|
78
|
+
const oldCode = hmrCssCopy.get(file);
|
|
79
|
+
// Save a copy of the current CSS for future updates
|
|
80
|
+
hmrCssCopy.set(file, code);
|
|
81
|
+
if (!oldCode || !hmrCssQueue.has(file))
|
|
82
|
+
return;
|
|
83
|
+
hmrCssQueue.delete(file);
|
|
84
|
+
// Diff old code with new code and use the exported class names as a reference
|
|
85
|
+
// to find out how the resulting CSS classes are renamed. With this, we can
|
|
86
|
+
// update classes in the DOM without requesting a full rendering from the server.
|
|
87
|
+
// Example:
|
|
88
|
+
// Previous code => export const red = ".red_k3tz4_module";
|
|
89
|
+
// New code => export const red = ".red_t93kw_module";
|
|
90
|
+
const classRE = /export const (.+?) = "(.+?)"/g;
|
|
91
|
+
const oldClasses = [...oldCode.matchAll(classRE)];
|
|
92
|
+
const replacements = [];
|
|
93
|
+
for (const [, newKey, newClass] of code.matchAll(classRE)) {
|
|
94
|
+
const oldClass = oldClasses.find(([, oldKey]) => oldKey === newKey)?.[2];
|
|
95
|
+
if (oldClass && oldClass !== newClass) {
|
|
96
|
+
replacements.push([oldClass, newClass]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (replacements.length > 0) {
|
|
100
|
+
// This event asks the browser to replace old
|
|
101
|
+
// hash-based CSS classes with new ones.
|
|
102
|
+
// Example: from `.red_k3tz4_module` to `.red_t93kw_module`
|
|
103
|
+
server.ws.send({
|
|
104
|
+
type: 'custom',
|
|
105
|
+
event: EVENT_CSS_CLASSES,
|
|
106
|
+
data: { replacements },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
40
110
|
},
|
|
41
111
|
transformIndexHtml(html, { server }) {
|
|
42
112
|
// Add discovered styles during dev
|
|
43
113
|
if (server) {
|
|
44
|
-
const tags =
|
|
114
|
+
const tags = (isUsingCssModules
|
|
115
|
+
? [
|
|
116
|
+
{
|
|
117
|
+
tag: 'script',
|
|
118
|
+
attrs: { type: 'module' },
|
|
119
|
+
children: CSS_MODULES_HMR_INJECT,
|
|
120
|
+
},
|
|
121
|
+
]
|
|
122
|
+
: []);
|
|
45
123
|
const foundCssFiles = new Set();
|
|
46
124
|
for (const [key, value] of server.moduleGraph.idToModuleMap.entries()) {
|
|
47
125
|
if (
|
|
48
126
|
// Note: Some CSS-in-JS libraries use `.css.js`
|
|
49
127
|
// extension and we should match it here:
|
|
50
|
-
|
|
128
|
+
CSS_EXTENSIONS_RE.test(normalizePath(key).split('/').pop())) {
|
|
51
129
|
let { url, file, lastHMRTimestamp, importers } = value;
|
|
52
130
|
if (!foundCssFiles.has(file) &&
|
|
53
131
|
!Array.from(importers).some((importer) => foundCssFiles.has(importer.file))) {
|
|
@@ -112,5 +190,24 @@ export default function cssRsc() {
|
|
|
112
190
|
}
|
|
113
191
|
}
|
|
114
192
|
},
|
|
193
|
+
async handleHotUpdate({ modules, server }) {
|
|
194
|
+
if (modules.every((m) => CSS_MODULES_EXTENSIONS_RE.test(m.file || ''))) {
|
|
195
|
+
// Opt-out of Vite's default HMR for CSS Modules, we'll handle this manually
|
|
196
|
+
const file = modules[0].file;
|
|
197
|
+
hmrCssQueue.add(file);
|
|
198
|
+
// This event asks the browser to download fresh CSS files.
|
|
199
|
+
// Fetching these fresh CSS files will trigger another event
|
|
200
|
+
// from the `transform` hook to replace classes in the DOM.
|
|
201
|
+
server.ws.send({
|
|
202
|
+
type: 'custom',
|
|
203
|
+
event: EVENT_CSS_IMPORT,
|
|
204
|
+
data: {
|
|
205
|
+
ids: modules.map((m) => m.id),
|
|
206
|
+
timestamp: modules[0].lastHMRTimestamp || Date.now(),
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
},
|
|
115
212
|
};
|
|
116
213
|
}
|
|
@@ -49,7 +49,7 @@ export default () => {
|
|
|
49
49
|
async transform(code, id, options) {
|
|
50
50
|
if (config.command === 'build' &&
|
|
51
51
|
options?.ssr &&
|
|
52
|
-
|
|
52
|
+
/\/hydrogen\/.+platforms\/virtual\./.test(normalizePath(id))) {
|
|
53
53
|
const ms = new MagicString(code);
|
|
54
54
|
ms.replace('__HYDROGEN_ENTRY__', HYDROGEN_DEFAULT_SERVER_ENTRY);
|
|
55
55
|
if (!clientBuildPath) {
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "1.4.
|
|
1
|
+
export declare const LIB_VERSION = "1.4.4";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '1.4.
|
|
1
|
+
export const LIB_VERSION = '1.4.4';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Plugin } from 'vite';
|
|
1
|
+
import { type Plugin } from 'vite';
|
|
2
2
|
export default function cssRsc(): Plugin;
|
|
@@ -8,6 +8,31 @@ const magic_string_1 = __importDefault(require("magic-string"));
|
|
|
8
8
|
const vite_1 = require("vite");
|
|
9
9
|
const VITE_CSS_CHUNK_NAME = 'style.css';
|
|
10
10
|
const INJECT_STYLES_COMMENT = '<!--__INJECT_STYLES__-->';
|
|
11
|
+
const CSS_EXTENSIONS_RE = /\.(css|sass|scss|stylus|less)(\.|\?|$)/;
|
|
12
|
+
const CSS_MODULES_EXTENSIONS_RE = /\.module\.(css|sass|scss|stylus|less)(\?|$)/;
|
|
13
|
+
const EVENT_CSS_IMPORT = 'hydrogen-css-modules-update-imports';
|
|
14
|
+
const EVENT_CSS_CLASSES = 'hydrogen-css-modules-update-classes';
|
|
15
|
+
const CSS_MODULES_HMR_INJECT = `
|
|
16
|
+
import {createHotContext, injectQuery} from "/@vite/client";
|
|
17
|
+
|
|
18
|
+
if (!import.meta.hot) {
|
|
19
|
+
import.meta.hot = createHotContext("/index.html");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
import.meta.hot.on('${EVENT_CSS_IMPORT}', ({ids, timestamp}) => {
|
|
23
|
+
ids.forEach((id) => {
|
|
24
|
+
import(injectQuery(id, 't=' + timestamp));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
import.meta.hot.on('${EVENT_CSS_CLASSES}', ({replacements}) => {
|
|
29
|
+
replacements.forEach(([oldClass, newClass]) => {
|
|
30
|
+
document.querySelectorAll('.' + oldClass).forEach(node => {
|
|
31
|
+
node.classList.replace(oldClass, newClass);
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
`;
|
|
11
36
|
// Keep this in the outer scope to share it
|
|
12
37
|
// across client <> server builds.
|
|
13
38
|
let clientBuildPath;
|
|
@@ -21,6 +46,10 @@ let clientBuildPath;
|
|
|
21
46
|
*/
|
|
22
47
|
function cssRsc() {
|
|
23
48
|
let config;
|
|
49
|
+
let server;
|
|
50
|
+
let isUsingCssModules = false;
|
|
51
|
+
const hmrCssCopy = new Map();
|
|
52
|
+
const hmrCssQueue = new Set();
|
|
24
53
|
return {
|
|
25
54
|
name: 'hydrogen:css-rsc',
|
|
26
55
|
enforce: 'post',
|
|
@@ -32,6 +61,9 @@ function cssRsc() {
|
|
|
32
61
|
configResolved(_config) {
|
|
33
62
|
config = _config;
|
|
34
63
|
},
|
|
64
|
+
configureServer(_server) {
|
|
65
|
+
server = _server;
|
|
66
|
+
},
|
|
35
67
|
transform(code, id, options) {
|
|
36
68
|
if (options?.ssr && id.includes('index.html?raw')) {
|
|
37
69
|
// Mark the client build index.html to inject styles later
|
|
@@ -42,17 +74,63 @@ function cssRsc() {
|
|
|
42
74
|
map: s.generateMap({ file: id, source: id }),
|
|
43
75
|
};
|
|
44
76
|
}
|
|
77
|
+
// Manual HMR for CSS Modules
|
|
78
|
+
if (server && CSS_MODULES_EXTENSIONS_RE.test(id)) {
|
|
79
|
+
isUsingCssModules = true;
|
|
80
|
+
const file = id.split('?')[0];
|
|
81
|
+
// Note: this "CSS" file is actually JavaScript code.
|
|
82
|
+
// Get a copy of how this CSS was before the current update
|
|
83
|
+
const oldCode = hmrCssCopy.get(file);
|
|
84
|
+
// Save a copy of the current CSS for future updates
|
|
85
|
+
hmrCssCopy.set(file, code);
|
|
86
|
+
if (!oldCode || !hmrCssQueue.has(file))
|
|
87
|
+
return;
|
|
88
|
+
hmrCssQueue.delete(file);
|
|
89
|
+
// Diff old code with new code and use the exported class names as a reference
|
|
90
|
+
// to find out how the resulting CSS classes are renamed. With this, we can
|
|
91
|
+
// update classes in the DOM without requesting a full rendering from the server.
|
|
92
|
+
// Example:
|
|
93
|
+
// Previous code => export const red = ".red_k3tz4_module";
|
|
94
|
+
// New code => export const red = ".red_t93kw_module";
|
|
95
|
+
const classRE = /export const (.+?) = "(.+?)"/g;
|
|
96
|
+
const oldClasses = [...oldCode.matchAll(classRE)];
|
|
97
|
+
const replacements = [];
|
|
98
|
+
for (const [, newKey, newClass] of code.matchAll(classRE)) {
|
|
99
|
+
const oldClass = oldClasses.find(([, oldKey]) => oldKey === newKey)?.[2];
|
|
100
|
+
if (oldClass && oldClass !== newClass) {
|
|
101
|
+
replacements.push([oldClass, newClass]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (replacements.length > 0) {
|
|
105
|
+
// This event asks the browser to replace old
|
|
106
|
+
// hash-based CSS classes with new ones.
|
|
107
|
+
// Example: from `.red_k3tz4_module` to `.red_t93kw_module`
|
|
108
|
+
server.ws.send({
|
|
109
|
+
type: 'custom',
|
|
110
|
+
event: EVENT_CSS_CLASSES,
|
|
111
|
+
data: { replacements },
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
45
115
|
},
|
|
46
116
|
transformIndexHtml(html, { server }) {
|
|
47
117
|
// Add discovered styles during dev
|
|
48
118
|
if (server) {
|
|
49
|
-
const tags =
|
|
119
|
+
const tags = (isUsingCssModules
|
|
120
|
+
? [
|
|
121
|
+
{
|
|
122
|
+
tag: 'script',
|
|
123
|
+
attrs: { type: 'module' },
|
|
124
|
+
children: CSS_MODULES_HMR_INJECT,
|
|
125
|
+
},
|
|
126
|
+
]
|
|
127
|
+
: []);
|
|
50
128
|
const foundCssFiles = new Set();
|
|
51
129
|
for (const [key, value] of server.moduleGraph.idToModuleMap.entries()) {
|
|
52
130
|
if (
|
|
53
131
|
// Note: Some CSS-in-JS libraries use `.css.js`
|
|
54
132
|
// extension and we should match it here:
|
|
55
|
-
|
|
133
|
+
CSS_EXTENSIONS_RE.test((0, vite_1.normalizePath)(key).split('/').pop())) {
|
|
56
134
|
let { url, file, lastHMRTimestamp, importers } = value;
|
|
57
135
|
if (!foundCssFiles.has(file) &&
|
|
58
136
|
!Array.from(importers).some((importer) => foundCssFiles.has(importer.file))) {
|
|
@@ -117,6 +195,25 @@ function cssRsc() {
|
|
|
117
195
|
}
|
|
118
196
|
}
|
|
119
197
|
},
|
|
198
|
+
async handleHotUpdate({ modules, server }) {
|
|
199
|
+
if (modules.every((m) => CSS_MODULES_EXTENSIONS_RE.test(m.file || ''))) {
|
|
200
|
+
// Opt-out of Vite's default HMR for CSS Modules, we'll handle this manually
|
|
201
|
+
const file = modules[0].file;
|
|
202
|
+
hmrCssQueue.add(file);
|
|
203
|
+
// This event asks the browser to download fresh CSS files.
|
|
204
|
+
// Fetching these fresh CSS files will trigger another event
|
|
205
|
+
// from the `transform` hook to replace classes in the DOM.
|
|
206
|
+
server.ws.send({
|
|
207
|
+
type: 'custom',
|
|
208
|
+
event: EVENT_CSS_IMPORT,
|
|
209
|
+
data: {
|
|
210
|
+
ids: modules.map((m) => m.id),
|
|
211
|
+
timestamp: modules[0].lastHMRTimestamp || Date.now(),
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
},
|
|
120
217
|
};
|
|
121
218
|
}
|
|
122
219
|
exports.default = cssRsc;
|
|
@@ -54,7 +54,7 @@ exports.default = () => {
|
|
|
54
54
|
async transform(code, id, options) {
|
|
55
55
|
if (config.command === 'build' &&
|
|
56
56
|
options?.ssr &&
|
|
57
|
-
|
|
57
|
+
/\/hydrogen\/.+platforms\/virtual\./.test((0, vite_1.normalizePath)(id))) {
|
|
58
58
|
const ms = new magic_string_1.default(code);
|
|
59
59
|
ms.replace('__HYDROGEN_ENTRY__', vite_plugin_hydrogen_middleware_js_1.HYDROGEN_DEFAULT_SERVER_ENTRY);
|
|
60
60
|
if (!clientBuildPath) {
|
package/package.json
CHANGED
|
@@ -7,16 +7,13 @@
|
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=14"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.4.
|
|
10
|
+
"version": "1.4.4",
|
|
11
11
|
"description": "Modern custom Shopify storefronts",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"main": "dist/esnext/index.js",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": "./dist/esnext/index.js",
|
|
16
|
-
"./experimental":
|
|
17
|
-
"import": "./dist/esnext/experimental.js",
|
|
18
|
-
"require": "./dist/node/experimental.js"
|
|
19
|
-
},
|
|
16
|
+
"./experimental": "./dist/esnext/experimental.js",
|
|
20
17
|
"./plugin": {
|
|
21
18
|
"import": "./dist/esnext/framework/plugin.js",
|
|
22
19
|
"require": "./dist/node/framework/plugin.js"
|