druxt 0.25.0-dev.20261022212039 → 0.25.0-dev.20261023045951
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/README.md +35 -51
- package/dist/druxt.esm.js +25 -8
- package/dist/druxt.ssr.js +25 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -90,36 +90,9 @@ options list.
|
|
|
90
90
|
## Server cache
|
|
91
91
|
|
|
92
92
|
In production, the server keeps Drupal's responses between requests for as
|
|
93
|
-
long as Drupal's `Cache-Control` header allows
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
from the page cache maximum age (Administration > Configuration > Development >
|
|
97
|
-
Performance). At the default of 0, nothing is kept. A request with an
|
|
98
|
-
`Authorization` header or a Drupal session cookie never reads or fills the
|
|
99
|
-
cache. The cache is off under `nuxt dev`.
|
|
100
|
-
|
|
101
|
-
| Option | Type | Default | Description |
|
|
102
|
-
| --------------------- | --------- | ------------------- | ------------------------------------------------------------------- |
|
|
103
|
-
| `cache.content` | `boolean` | `false` | Also keep entities, collections, views and route lookups. |
|
|
104
|
-
| `cache.maxSize` | `number` | `52428800` (50 MB) | Bytes of responses kept per cache area. The least recently used go. |
|
|
105
|
-
| `cache.ttl` | `number` | | Seconds a response may be kept at most. `0` keeps nothing. |
|
|
106
|
-
| `cache.secret` | `string` | | Turns on `POST /_druxt/cache/clear`. |
|
|
107
|
-
| `cache.sessionCookie` | `string` | `'S?SESS[0-9a-f]+'` | A pattern for the session cookie name, for a proxy that renames it. |
|
|
108
|
-
|
|
109
|
-
Clear the cache from the app with `this.$store.dispatch('druxt/clearCache')`,
|
|
110
|
-
or from Drupal by sending `POST /_druxt/cache/clear` with the secret in an
|
|
111
|
-
`X-Druxt-Secret` header. Each Nuxt process has its own cache, so a site with
|
|
112
|
-
several processes clears each one.
|
|
113
|
-
|
|
114
|
-
The endpoint is server middleware, so list Druxt, or the module that adds it
|
|
115
|
-
such as `druxt-site`, under `modules`. Nuxt runs `buildModules` only while it
|
|
116
|
-
builds, so under `nuxt start` the endpoint would answer 404.
|
|
117
|
-
|
|
118
|
-
### Caching content
|
|
119
|
-
|
|
120
|
-
`cache.content` extends the cache to every other request Druxt sends Drupal:
|
|
121
|
-
entities, collections, views and route lookups. A second visitor to a page
|
|
122
|
-
then costs Drupal nothing until the page's lifetime runs out.
|
|
93
|
+
long as Drupal's `Cache-Control` header allows: the JSON:API index and menus,
|
|
94
|
+
and with `cache.content` every other response. Drupal sets that header from
|
|
95
|
+
its page cache maximum age, so at the default of 0 nothing is kept.
|
|
123
96
|
|
|
124
97
|
```js
|
|
125
98
|
// nuxt.config.js
|
|
@@ -130,35 +103,46 @@ export default {
|
|
|
130
103
|
};
|
|
131
104
|
```
|
|
132
105
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
106
|
+
| Option | Type | Default | Description |
|
|
107
|
+
| --------------------- | --------- | ------------------- | -------------------------------------------------------------------------------- |
|
|
108
|
+
| `cache.content` | `boolean` | `false` | Also keep entities, collections, views and route lookups. |
|
|
109
|
+
| `cache.maxSize` | `number` | `52428800` (50 MB) | Bytes of responses kept per cache area and consumer. The least recently used go. |
|
|
110
|
+
| `cache.ttl` | `number` | | Seconds a response may be kept at most. `0` keeps nothing. |
|
|
111
|
+
| `cache.secret` | `string` | | Turns on `POST /_druxt/cache/clear`. |
|
|
112
|
+
| `cache.sessionCookie` | `string` | `'S?SESS[0-9a-f]+'` | A pattern for the session cookie name, for a proxy that renames it. |
|
|
113
|
+
|
|
114
|
+
- A request with an `Authorization` header or a Drupal session cookie skips
|
|
115
|
+
the cache, and `nuxt dev` runs without it.
|
|
116
|
+
- Only successful responses are kept. A `bypassCache` dispatch fetches afresh
|
|
117
|
+
and stores the result.
|
|
118
|
+
- A full cache area takes about three times `cache.maxSize` in server memory,
|
|
119
|
+
and a response larger than the limit is not kept.
|
|
120
|
+
- Clear it with `druxt/clearCache`, or from Drupal with
|
|
121
|
+
`POST /_druxt/cache/clear` and the secret in an `X-Druxt-Secret` header.
|
|
122
|
+
Each Nuxt process has its own cache to clear.
|
|
123
|
+
- The clear endpoint is server middleware, so list Druxt, or `druxt-site`,
|
|
124
|
+
under `modules`. Nuxt skips `buildModules` under `nuxt start`.
|
|
125
|
+
|
|
126
|
+
The [caching guide](https://druxtjs.org/how-to/caching) covers the cache in
|
|
127
|
+
more depth.
|
|
144
128
|
|
|
145
129
|
### Clearing from Drupal with Purge
|
|
146
130
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
131
|
+
With `cache.content` on, an edit can take up to the page cache maximum age, or
|
|
132
|
+
`cache.ttl` if that is shorter, to reach anonymous visitors, unless Drupal
|
|
133
|
+
clears the cache. The
|
|
134
|
+
[Purge](https://www.drupal.org/project/purge) module can send that request on
|
|
135
|
+
every save. Enable `purge`, `purge_purger_http`, `purge_queuer_coretags` and
|
|
136
|
+
`purge_processor_lateruntime`, then add the bundled HTTP purger:
|
|
151
137
|
|
|
152
138
|
```sh
|
|
153
139
|
drush p:purger-add httpbundled
|
|
154
140
|
```
|
|
155
141
|
|
|
156
|
-
|
|
157
|
-
`/_druxt/cache/clear`,
|
|
158
|
-
invalidation type `tag`.
|
|
159
|
-
|
|
160
|
-
next batch. Keep the secret out of exported configuration: set it from
|
|
161
|
-
`settings.php` as a `$config` override.
|
|
142
|
+
Point it at the Nuxt server's host and port, as Drupal reaches it, with the
|
|
143
|
+
path `/_druxt/cache/clear`, the method `POST`, the `X-Druxt-Secret` header and
|
|
144
|
+
the invalidation type `tag`. Set the secret from `settings.php` as
|
|
145
|
+
a `$config` override, not in exported configuration.
|
|
162
146
|
|
|
163
147
|
## DruxtClient
|
|
164
148
|
|
package/dist/druxt.esm.js
CHANGED
|
@@ -553,7 +553,7 @@ const cacheClearHandler = (secret) => (req, res) => {
|
|
|
553
553
|
};
|
|
554
554
|
|
|
555
555
|
var name = "druxt";
|
|
556
|
-
var version = "0.25.0-dev.
|
|
556
|
+
var version = "0.25.0-dev.20261023045951";
|
|
557
557
|
var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
|
|
558
558
|
var keywords = [
|
|
559
559
|
"cms",
|
|
@@ -614,7 +614,7 @@ var dependencies = {
|
|
|
614
614
|
};
|
|
615
615
|
var devDependencies = {
|
|
616
616
|
"@storybook/addon-docs": "^6.5.16",
|
|
617
|
-
"druxt-test-utils": "0.2.16-dev.
|
|
617
|
+
"druxt-test-utils": "0.2.16-dev.20261023045951"
|
|
618
618
|
};
|
|
619
619
|
var peerDependencies = {
|
|
620
620
|
axios: ">=0.34.0",
|
|
@@ -782,6 +782,20 @@ const getDrupalJsonApiParams = (query) => {
|
|
|
782
782
|
return new DrupalJsonApiParams().initialize(query);
|
|
783
783
|
};
|
|
784
784
|
|
|
785
|
+
const includePaths = (include) => (Array.isArray(include) ? include : String(include || "").split(",")).map((path) => String(path).trim()).filter((path) => path);
|
|
786
|
+
const topIncludes = (include) => Array.from(new Set(includePaths(include).map((path) => path.split(".")[0])));
|
|
787
|
+
const subIncludes = (include, key) => includePaths(include).filter((path) => path.startsWith(`${key}.`)).map((path) => path.slice(key.length + 1)).join(",");
|
|
788
|
+
const fieldsWithIncludes = (fields, include) => Array.from(new Set([...String(fields).split(","), ...topIncludes(include)])).filter((field) => field).join(",");
|
|
789
|
+
const includesFor = (include, fields, relationships = []) => {
|
|
790
|
+
if (!include || typeof fields !== "string")
|
|
791
|
+
return include;
|
|
792
|
+
const listed = fields.split(",");
|
|
793
|
+
return includePaths(include).filter((path) => {
|
|
794
|
+
const key = path.split(".")[0];
|
|
795
|
+
return listed.includes(key) || relationships.includes(key);
|
|
796
|
+
}).join(",");
|
|
797
|
+
};
|
|
798
|
+
|
|
785
799
|
const dehydrateResources = ({ commit, queryObject, resources, prefix }) => {
|
|
786
800
|
return (resources || []).map((data) => {
|
|
787
801
|
const link = decodeURI(((data.links || {}).self || {}).href || "");
|
|
@@ -955,22 +969,25 @@ const DruxtStore = ({ store }) => {
|
|
|
955
969
|
const queryObject = getDrupalJsonApiParams(query).getQueryObject();
|
|
956
970
|
queryObject.include = Array.isArray(queryObject.include) ? queryObject.include.join(",") : queryObject.include;
|
|
957
971
|
if (queryObject.include && typeof (queryObject.fields || {})[type] === "string") {
|
|
958
|
-
|
|
959
|
-
const includes = queryObject.include.split(",").filter((s) => s && !s.includes("."));
|
|
960
|
-
queryObject.fields[type] = Array.from(new Set([...fields2, ...includes])).filter((s) => s).join(",");
|
|
972
|
+
queryObject.fields[type] = fieldsWithIncludes(queryObject.fields[type], queryObject.include);
|
|
961
973
|
}
|
|
974
|
+
const includeFor = (related, include) => {
|
|
975
|
+
const stored2 = ((state.resources[related.type] || {})[related.id] || {})[prefix];
|
|
976
|
+
const relationships = Object.keys(((stored2 || {}).data || {}).relationships || {});
|
|
977
|
+
return includesFor(include, (queryObject.fields || {})[related.type], relationships);
|
|
978
|
+
};
|
|
962
979
|
let included = [];
|
|
963
980
|
if (queryObject.include && storedResource && !bypassCache) {
|
|
964
|
-
const resources = await Promise.all(queryObject.include
|
|
981
|
+
const resources = await Promise.all(topIncludes(queryObject.include).filter((s) => Object.keys(storedResource.data.relationships || {}).includes(s)).map((key) => {
|
|
965
982
|
let { data } = storedResource.data.relationships[key];
|
|
966
983
|
data = Array.isArray(data) ? data : [data];
|
|
967
|
-
const include = queryObject.include
|
|
984
|
+
const include = subIncludes(queryObject.include, key);
|
|
968
985
|
return data.filter((o) => typeof o === "object" && o).map((o) => {
|
|
969
986
|
return dispatch("getResource", {
|
|
970
987
|
id: o.id,
|
|
971
988
|
prefix,
|
|
972
989
|
type: o.type,
|
|
973
|
-
query: { ...queryObject, include }
|
|
990
|
+
query: { ...queryObject, include: includeFor(o, include) }
|
|
974
991
|
});
|
|
975
992
|
});
|
|
976
993
|
}).flat());
|
package/dist/druxt.ssr.js
CHANGED
|
@@ -566,7 +566,7 @@ const cacheClearHandler = (secret) => (req, res) => {
|
|
|
566
566
|
};
|
|
567
567
|
|
|
568
568
|
var name = "druxt";
|
|
569
|
-
var version = "0.25.0-dev.
|
|
569
|
+
var version = "0.25.0-dev.20261023045951";
|
|
570
570
|
var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
|
|
571
571
|
var keywords = [
|
|
572
572
|
"cms",
|
|
@@ -627,7 +627,7 @@ var dependencies = {
|
|
|
627
627
|
};
|
|
628
628
|
var devDependencies = {
|
|
629
629
|
"@storybook/addon-docs": "^6.5.16",
|
|
630
|
-
"druxt-test-utils": "0.2.16-dev.
|
|
630
|
+
"druxt-test-utils": "0.2.16-dev.20261023045951"
|
|
631
631
|
};
|
|
632
632
|
var peerDependencies = {
|
|
633
633
|
axios: ">=0.34.0",
|
|
@@ -795,6 +795,20 @@ const getDrupalJsonApiParams = (query) => {
|
|
|
795
795
|
return new drupalJsonapiParams.DrupalJsonApiParams().initialize(query);
|
|
796
796
|
};
|
|
797
797
|
|
|
798
|
+
const includePaths = (include) => (Array.isArray(include) ? include : String(include || "").split(",")).map((path) => String(path).trim()).filter((path) => path);
|
|
799
|
+
const topIncludes = (include) => Array.from(new Set(includePaths(include).map((path) => path.split(".")[0])));
|
|
800
|
+
const subIncludes = (include, key) => includePaths(include).filter((path) => path.startsWith(`${key}.`)).map((path) => path.slice(key.length + 1)).join(",");
|
|
801
|
+
const fieldsWithIncludes = (fields, include) => Array.from(new Set([...String(fields).split(","), ...topIncludes(include)])).filter((field) => field).join(",");
|
|
802
|
+
const includesFor = (include, fields, relationships = []) => {
|
|
803
|
+
if (!include || typeof fields !== "string")
|
|
804
|
+
return include;
|
|
805
|
+
const listed = fields.split(",");
|
|
806
|
+
return includePaths(include).filter((path) => {
|
|
807
|
+
const key = path.split(".")[0];
|
|
808
|
+
return listed.includes(key) || relationships.includes(key);
|
|
809
|
+
}).join(",");
|
|
810
|
+
};
|
|
811
|
+
|
|
798
812
|
const dehydrateResources = ({ commit, queryObject, resources, prefix }) => {
|
|
799
813
|
return (resources || []).map((data) => {
|
|
800
814
|
const link = decodeURI(((data.links || {}).self || {}).href || "");
|
|
@@ -968,22 +982,25 @@ const DruxtStore = ({ store }) => {
|
|
|
968
982
|
const queryObject = getDrupalJsonApiParams(query).getQueryObject();
|
|
969
983
|
queryObject.include = Array.isArray(queryObject.include) ? queryObject.include.join(",") : queryObject.include;
|
|
970
984
|
if (queryObject.include && typeof (queryObject.fields || {})[type] === "string") {
|
|
971
|
-
|
|
972
|
-
const includes = queryObject.include.split(",").filter((s) => s && !s.includes("."));
|
|
973
|
-
queryObject.fields[type] = Array.from(new Set([...fields2, ...includes])).filter((s) => s).join(",");
|
|
985
|
+
queryObject.fields[type] = fieldsWithIncludes(queryObject.fields[type], queryObject.include);
|
|
974
986
|
}
|
|
987
|
+
const includeFor = (related, include) => {
|
|
988
|
+
const stored2 = ((state.resources[related.type] || {})[related.id] || {})[prefix];
|
|
989
|
+
const relationships = Object.keys(((stored2 || {}).data || {}).relationships || {});
|
|
990
|
+
return includesFor(include, (queryObject.fields || {})[related.type], relationships);
|
|
991
|
+
};
|
|
975
992
|
let included = [];
|
|
976
993
|
if (queryObject.include && storedResource && !bypassCache) {
|
|
977
|
-
const resources = await Promise.all(queryObject.include
|
|
994
|
+
const resources = await Promise.all(topIncludes(queryObject.include).filter((s) => Object.keys(storedResource.data.relationships || {}).includes(s)).map((key) => {
|
|
978
995
|
let { data } = storedResource.data.relationships[key];
|
|
979
996
|
data = Array.isArray(data) ? data : [data];
|
|
980
|
-
const include = queryObject.include
|
|
997
|
+
const include = subIncludes(queryObject.include, key);
|
|
981
998
|
return data.filter((o) => typeof o === "object" && o).map((o) => {
|
|
982
999
|
return dispatch("getResource", {
|
|
983
1000
|
id: o.id,
|
|
984
1001
|
prefix,
|
|
985
1002
|
type: o.type,
|
|
986
|
-
query: { ...queryObject, include }
|
|
1003
|
+
query: { ...queryObject, include: includeFor(o, include) }
|
|
987
1004
|
});
|
|
988
1005
|
});
|
|
989
1006
|
}).flat());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "druxt",
|
|
3
|
-
"version": "0.25.0-dev.
|
|
3
|
+
"version": "0.25.0-dev.20261023045951",
|
|
4
4
|
"description": "The Fully Decoupled Drupal Framework for Nuxt.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cms",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@storybook/addon-docs": "^6.5.16",
|
|
64
|
-
"druxt-test-utils": "0.2.16-dev.
|
|
64
|
+
"druxt-test-utils": "0.2.16-dev.20261023045951"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"axios": ">=0.34.0",
|