apostrophe 3.16.0 → 3.17.0
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/.eslintignore +3 -1
- package/CHANGELOG.md +23 -1
- package/index.js +5 -4
- package/lib/moog.js +14 -1
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +3 -1
- package/modules/@apostrophecms/asset/index.js +213 -101
- package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +3 -3
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.config.js +30 -12
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.es5.js +1 -1
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.scss.js +6 -2
- package/modules/@apostrophecms/asset/lib/webpack/utils.js +266 -0
- package/modules/@apostrophecms/asset/views/scripts.html +1 -0
- package/modules/@apostrophecms/asset/views/stylesheets.html +1 -0
- package/modules/@apostrophecms/doc/index.js +64 -0
- package/modules/@apostrophecms/doc-type/index.js +35 -0
- package/modules/@apostrophecms/i18n/i18n/en.json +2 -0
- package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +7 -0
- package/modules/@apostrophecms/login/index.js +4 -0
- package/modules/@apostrophecms/schema/index.js +40 -49
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +67 -0
- package/modules/@apostrophecms/template/index.js +14 -5
- package/modules/@apostrophecms/template/lib/bundlesLoader.js +158 -0
- package/modules/@apostrophecms/template/views/outerLayoutBase.html +6 -0
- package/modules/@apostrophecms/widget-type/index.js +21 -0
- package/package.json +1 -1
- package/test/areas.js +2 -1
- package/test/assets.js +307 -3
- package/test/docs.js +67 -2
- package/test/modules/bundle/index.js +7 -0
- package/test/modules/bundle-page/index.js +32 -0
- package/test/modules/bundle-page/ui/src/extra.js +1 -0
- package/test/modules/bundle-page/ui/src/extra.scss +0 -0
- package/test/modules/bundle-page/views/index.html +9 -0
- package/test/modules/bundle-page/views/show.html +10 -0
- package/test/modules/bundle-widget/index.js +27 -0
- package/test/modules/bundle-widget/ui/src/extra2.js +1 -0
- package/test/modules/bundle-widget/views/widget.html +1 -0
- package/test/pieces.js +38 -12
- package/test/public/static-test.txt +0 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- Errors for the entire object field are not interesting,
|
|
3
|
+
let the relevant subfield's error shine on its own -->
|
|
4
|
+
<AposInputWrapper
|
|
5
|
+
:field="field"
|
|
6
|
+
:error="null"
|
|
7
|
+
:uid="uid"
|
|
8
|
+
:display-options="displayOptions"
|
|
9
|
+
>
|
|
10
|
+
<template #body>
|
|
11
|
+
<div class="apos-input-object">
|
|
12
|
+
<div class="apos-input-wrapper">
|
|
13
|
+
<AposSchema
|
|
14
|
+
:schema="field.schema"
|
|
15
|
+
:trigger-validation="triggerValidation"
|
|
16
|
+
:utility-rail="false"
|
|
17
|
+
v-model="schemaInput"
|
|
18
|
+
ref="schema"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
</AposInputWrapper>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script>
|
|
27
|
+
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin.js';
|
|
28
|
+
import { klona } from 'klona';
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
name: 'AposInputObject',
|
|
32
|
+
mixins: [ AposInputMixin ],
|
|
33
|
+
data () {
|
|
34
|
+
const next = this.value ? this.value.data : (this.field.def || {});
|
|
35
|
+
return {
|
|
36
|
+
schemaInput: {
|
|
37
|
+
data: next
|
|
38
|
+
},
|
|
39
|
+
next
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
watch: {
|
|
43
|
+
schemaInput() {
|
|
44
|
+
this.next = this.schemaInput.data;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
methods: {
|
|
48
|
+
validate (value) {
|
|
49
|
+
if (this.schemaInput.hasErrors) {
|
|
50
|
+
return 'invalid';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<style scoped>
|
|
58
|
+
.apos-input-object {
|
|
59
|
+
border-left: 1px solid var(--a-base-9);
|
|
60
|
+
}
|
|
61
|
+
.apos-input-wrapper {
|
|
62
|
+
margin: 20px 0 0 19px;
|
|
63
|
+
}
|
|
64
|
+
.apos-input-object ::v-deep .apos-schema .apos-field {
|
|
65
|
+
margin-bottom: 30px;
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
@@ -119,6 +119,7 @@ module.exports = {
|
|
|
119
119
|
},
|
|
120
120
|
methods(self) {
|
|
121
121
|
return {
|
|
122
|
+
...require('./lib/bundlesLoader')(self),
|
|
122
123
|
|
|
123
124
|
// Add helpers in the namespace for a particular module.
|
|
124
125
|
// They will be visible in nunjucks at
|
|
@@ -630,8 +631,6 @@ module.exports = {
|
|
|
630
631
|
// async function.
|
|
631
632
|
|
|
632
633
|
async renderPageForModule(req, template, data, module) {
|
|
633
|
-
|
|
634
|
-
let content;
|
|
635
634
|
let scene = req.user ? 'apos' : 'public';
|
|
636
635
|
if (req.scene) {
|
|
637
636
|
scene = req.scene;
|
|
@@ -699,15 +698,25 @@ module.exports = {
|
|
|
699
698
|
}
|
|
700
699
|
|
|
701
700
|
try {
|
|
702
|
-
content = await module.render(req, template, args);
|
|
701
|
+
const content = await module.render(req, template, args);
|
|
702
|
+
|
|
703
|
+
const filledContent = self.insertBundlesMarkup({
|
|
704
|
+
page: req.data.bestPage,
|
|
705
|
+
scene,
|
|
706
|
+
template,
|
|
707
|
+
content,
|
|
708
|
+
scriptsPlaceholder: req.scriptsPlaceholder,
|
|
709
|
+
stylesheetsPlaceholder: req.stylesheetsPlaceholder,
|
|
710
|
+
widgetsBundles: req.widgetsBundles
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
return filledContent;
|
|
703
714
|
} catch (e) {
|
|
704
715
|
// The page template threw an exception. Log where it
|
|
705
716
|
// occurred for easier debugging
|
|
706
717
|
return error(e);
|
|
707
718
|
}
|
|
708
719
|
|
|
709
|
-
return content;
|
|
710
|
-
|
|
711
720
|
function error(e) {
|
|
712
721
|
self.logError(req, e);
|
|
713
722
|
req.statusCode = 500;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const { stripIndent } = require('common-tags');
|
|
2
|
+
|
|
3
|
+
module.exports = (self) => {
|
|
4
|
+
function insertBundlesMarkup({
|
|
5
|
+
page = {},
|
|
6
|
+
template = '',
|
|
7
|
+
scene,
|
|
8
|
+
content,
|
|
9
|
+
scriptsPlaceholder,
|
|
10
|
+
stylesheetsPlaceholder,
|
|
11
|
+
widgetsBundles = {}
|
|
12
|
+
}) {
|
|
13
|
+
const renderMarkup = renderBundleMarkup(
|
|
14
|
+
self.apos.template.safe,
|
|
15
|
+
self.apos.asset.getAssetBaseUrl()
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (!scriptsPlaceholder && !stylesheetsPlaceholder) {
|
|
19
|
+
return content;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { es5 } = self.apos.asset.options;
|
|
23
|
+
const { extraBundles } = self.apos.asset;
|
|
24
|
+
|
|
25
|
+
const jsMainBundle = renderMarkup({
|
|
26
|
+
fileName: scene,
|
|
27
|
+
ext: 'js',
|
|
28
|
+
es5
|
|
29
|
+
});
|
|
30
|
+
const cssMainBundle = renderMarkup({
|
|
31
|
+
fileName: scene,
|
|
32
|
+
ext: 'css'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (scene === 'apos') {
|
|
36
|
+
return loadAllBundles({
|
|
37
|
+
content,
|
|
38
|
+
scriptsPlaceholder,
|
|
39
|
+
stylesheetsPlaceholder,
|
|
40
|
+
extraBundles,
|
|
41
|
+
renderMarkup,
|
|
42
|
+
jsMainBundle,
|
|
43
|
+
cssMainBundle,
|
|
44
|
+
es5
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const templateType = template.substring(template.lastIndexOf(':') + 1);
|
|
49
|
+
const pageModule = page.type && self.apos.modules[page.type];
|
|
50
|
+
const { webpack = {} } = pageModule ? pageModule.__meta : {};
|
|
51
|
+
|
|
52
|
+
const configs = Object.values(webpack || {}).reduce((acc, config) => ({
|
|
53
|
+
...acc,
|
|
54
|
+
...config && config.bundles
|
|
55
|
+
}), widgetsBundles);
|
|
56
|
+
|
|
57
|
+
const { jsBundles, cssBundles } = Object.entries(configs)
|
|
58
|
+
.reduce((acc, [ name, { templates } ]) => {
|
|
59
|
+
if (templates && !templates.includes(templateType)) {
|
|
60
|
+
return acc;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const jsMarkup = scriptsPlaceholder &&
|
|
64
|
+
extraBundles.js.includes(name) &&
|
|
65
|
+
renderMarkup({
|
|
66
|
+
fileName: name,
|
|
67
|
+
ext: 'js',
|
|
68
|
+
es5
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const cssMarkup = stylesheetsPlaceholder &&
|
|
72
|
+
extraBundles.css.includes(name) &&
|
|
73
|
+
renderMarkup({
|
|
74
|
+
fileName: name,
|
|
75
|
+
ext: 'css'
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
jsBundles: stripIndent`
|
|
80
|
+
${acc.jsBundles}
|
|
81
|
+
${jsMarkup || ''}
|
|
82
|
+
`,
|
|
83
|
+
cssBundles: stripIndent`
|
|
84
|
+
${acc.cssBundles}
|
|
85
|
+
${cssMarkup || ''}
|
|
86
|
+
`
|
|
87
|
+
};
|
|
88
|
+
}, {
|
|
89
|
+
jsBundles: jsMainBundle,
|
|
90
|
+
cssBundles: cssMainBundle
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return content
|
|
94
|
+
.replace(scriptsPlaceholder, jsBundles)
|
|
95
|
+
.replace(stylesheetsPlaceholder, cssBundles);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { insertBundlesMarkup };
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function renderBundleMarkup (safe, base) {
|
|
102
|
+
return ({
|
|
103
|
+
fileName, ext = 'js', es5 = false
|
|
104
|
+
}) => {
|
|
105
|
+
if (ext === 'css') {
|
|
106
|
+
return safe(stripIndent`
|
|
107
|
+
<link href="${base}/${fileName}-bundle.css" rel="stylesheet" />
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (es5) {
|
|
112
|
+
return safe(stripIndent`
|
|
113
|
+
<script nomodule src="${base}/${fileName}-nomodule-bundle.${ext}"></script>
|
|
114
|
+
<script type="module" src="${base}/${fileName}-module-bundle.${ext}"></script>
|
|
115
|
+
`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return safe(stripIndent`
|
|
119
|
+
<script src="${base}/${fileName}-module-bundle.${ext}"></script>
|
|
120
|
+
`);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function loadAllBundles({
|
|
125
|
+
content,
|
|
126
|
+
extraBundles,
|
|
127
|
+
scriptsPlaceholder,
|
|
128
|
+
stylesheetsPlaceholder,
|
|
129
|
+
jsMainBundle,
|
|
130
|
+
cssMainBundle,
|
|
131
|
+
renderMarkup,
|
|
132
|
+
es5
|
|
133
|
+
}) {
|
|
134
|
+
const reduceToMarkup = (acc, bundle, ext) => {
|
|
135
|
+
const bundleMarkup = renderMarkup({
|
|
136
|
+
fileName: bundle.replace(`.${ext}`, ''),
|
|
137
|
+
ext,
|
|
138
|
+
es5
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return stripIndent`
|
|
142
|
+
${acc}
|
|
143
|
+
${bundleMarkup}
|
|
144
|
+
`;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const jsBundles = extraBundles.js.reduce(
|
|
148
|
+
(acc, bundle) => reduceToMarkup(acc, bundle, 'js'), jsMainBundle
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const cssBundles = extraBundles.css.reduce(
|
|
152
|
+
(acc, bundle) => reduceToMarkup(acc, bundle, 'css'), cssMainBundle
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return content
|
|
156
|
+
.replace(scriptsPlaceholder, jsBundles)
|
|
157
|
+
.replace(stylesheetsPlaceholder, cssBundles);
|
|
158
|
+
}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
{% endblock %}
|
|
6
6
|
{% component '@apostrophecms/template:inject' with { where: 'head', end: 'prepend' } %}
|
|
7
7
|
<title>{% block title %}{{ data.piece.title or data.page.title }}{% endblock %}</title>
|
|
8
|
+
|
|
9
|
+
{# This call is still here for backwards compatibility, but does nothing #}
|
|
8
10
|
{{ apos.asset.stylesheets(data.scene) }}
|
|
11
|
+
|
|
9
12
|
{% block standardHead %}
|
|
10
13
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
11
14
|
{% endblock %}
|
|
@@ -40,7 +43,10 @@
|
|
|
40
43
|
<div id="apos-modals"></div>
|
|
41
44
|
{% endif %}
|
|
42
45
|
{# Scripts must load after apos-modal in the DOM #}
|
|
46
|
+
|
|
47
|
+
{# This call is still here for backwards compatibility, but does nothing #}
|
|
43
48
|
{{ apos.asset.scripts(data.scene) }}
|
|
49
|
+
|
|
44
50
|
{# For project-level webpack injection in dev environments #}
|
|
45
51
|
{% block afterAposScripts %}{% endblock %}
|
|
46
52
|
{# Automatically does nothing in production #}
|
|
@@ -178,6 +178,11 @@ module.exports = {
|
|
|
178
178
|
// async, as are all functions that invoke a nunjucks render in
|
|
179
179
|
// Apostrophe 3.x.
|
|
180
180
|
async output(req, widget, options, _with) {
|
|
181
|
+
req.widgetsBundles = {
|
|
182
|
+
...req.widgetsBundles || {},
|
|
183
|
+
...self.getWidgetsBundles(`${widget.type}-widget`)
|
|
184
|
+
};
|
|
185
|
+
|
|
181
186
|
return self.render(req, self.template, {
|
|
182
187
|
widget: widget,
|
|
183
188
|
options: options,
|
|
@@ -186,6 +191,22 @@ module.exports = {
|
|
|
186
191
|
});
|
|
187
192
|
},
|
|
188
193
|
|
|
194
|
+
getWidgetsBundles (widgetType) {
|
|
195
|
+
const widget = self.apos.modules[widgetType];
|
|
196
|
+
|
|
197
|
+
if (!widget) {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return Object.values(widget.__meta.webpack || {})
|
|
202
|
+
.reduce((acc, config) => {
|
|
203
|
+
return {
|
|
204
|
+
...acc,
|
|
205
|
+
...config && config.bundles
|
|
206
|
+
};
|
|
207
|
+
}, {});
|
|
208
|
+
},
|
|
209
|
+
|
|
189
210
|
// Load relationships and carry out any other necessary async
|
|
190
211
|
// actions for our type of widget, as long as it is
|
|
191
212
|
// not forbidden due to the `neverLoad` option or the
|
package/package.json
CHANGED
package/test/areas.js
CHANGED
|
@@ -232,7 +232,8 @@ describe('Areas', function() {
|
|
|
232
232
|
assert(doc.main._rendered);
|
|
233
233
|
assert(!doc.main.items);
|
|
234
234
|
|
|
235
|
-
//
|
|
235
|
+
// TODO the approach in this test can't cover array or object area rendering
|
|
236
|
+
// properly without a further overhaul (not a new problem).
|
|
236
237
|
// if (doc.moreAreas) {
|
|
237
238
|
// doc.moreAreas.forEach(area => {
|
|
238
239
|
// assert(area.someWidgets._rendered);
|
package/test/assets.js
CHANGED
|
@@ -1,18 +1,101 @@
|
|
|
1
1
|
const t = require('../test-lib/test.js');
|
|
2
2
|
const assert = require('assert');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
checkModulesWebpackConfig,
|
|
8
|
+
getWebpackExtensions,
|
|
9
|
+
fillExtraBundles
|
|
10
|
+
} = require('../modules/@apostrophecms/asset/lib/webpack/utils');
|
|
11
|
+
|
|
3
12
|
let apos;
|
|
4
13
|
|
|
14
|
+
const badModules = {
|
|
15
|
+
badModuleConfig: {
|
|
16
|
+
webpack: {
|
|
17
|
+
badprop: {}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
badModuleConfig2: {
|
|
21
|
+
webpack: []
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const pagesToInsert = (homeId) => ([
|
|
26
|
+
{
|
|
27
|
+
_id: 'parent:en:published',
|
|
28
|
+
aposLocale: 'en:published',
|
|
29
|
+
metaType: 'doc',
|
|
30
|
+
aposDocId: 'parent',
|
|
31
|
+
type: 'bundle-page',
|
|
32
|
+
slug: '/bundle',
|
|
33
|
+
visibility: 'public',
|
|
34
|
+
path: `${homeId.replace(':en:published', '')}/bundle`,
|
|
35
|
+
level: 1,
|
|
36
|
+
rank: 0,
|
|
37
|
+
main: {
|
|
38
|
+
_id: 'areaId',
|
|
39
|
+
metaType: 'area',
|
|
40
|
+
items: [
|
|
41
|
+
{
|
|
42
|
+
_id: 'widgetId',
|
|
43
|
+
metaType: 'widget',
|
|
44
|
+
type: 'bundle'
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
_id: 'child:en:published',
|
|
51
|
+
title: 'Bundle',
|
|
52
|
+
aposLocale: 'en:published',
|
|
53
|
+
metaType: 'doc',
|
|
54
|
+
aposDocId: 'child',
|
|
55
|
+
type: 'bundle',
|
|
56
|
+
slug: 'child',
|
|
57
|
+
visibility: 'public'
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const modules = {
|
|
62
|
+
'@apostrophecms/page': {
|
|
63
|
+
options: {
|
|
64
|
+
park: [],
|
|
65
|
+
types: [
|
|
66
|
+
{
|
|
67
|
+
name: 'bundle-page',
|
|
68
|
+
label: 'Bundle Page'
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
bundle: {},
|
|
74
|
+
'bundle-page': {},
|
|
75
|
+
'bundle-widget': {}
|
|
76
|
+
};
|
|
77
|
+
|
|
5
78
|
describe('Assets', function() {
|
|
79
|
+
const {
|
|
80
|
+
publicFolderPath,
|
|
81
|
+
getScriptMarkup,
|
|
82
|
+
getStylesheetMarkup,
|
|
83
|
+
expectedBundlesNames,
|
|
84
|
+
deleteBuiltFolders,
|
|
85
|
+
allBundlesAreIncluded
|
|
86
|
+
} = loadUtils();
|
|
6
87
|
|
|
7
88
|
after(async function() {
|
|
89
|
+
await deleteBuiltFolders(publicFolderPath, true);
|
|
8
90
|
return t.destroy(apos);
|
|
9
91
|
});
|
|
10
92
|
|
|
11
|
-
this.timeout(
|
|
93
|
+
this.timeout(90000);
|
|
12
94
|
|
|
13
|
-
it('should
|
|
95
|
+
it('should exist on the apos object', async function() {
|
|
14
96
|
apos = await t.create({
|
|
15
|
-
root: module
|
|
97
|
+
root: module,
|
|
98
|
+
modules
|
|
16
99
|
});
|
|
17
100
|
assert(apos.asset);
|
|
18
101
|
});
|
|
@@ -21,4 +104,225 @@ describe('Assets', function() {
|
|
|
21
104
|
const text = await apos.http.get('/static-test.txt');
|
|
22
105
|
assert(text.match(/served/));
|
|
23
106
|
});
|
|
107
|
+
|
|
108
|
+
it('should check that webpack configs in modules are well formatted', async function () {
|
|
109
|
+
const translate = apos.task.getReq().t;
|
|
110
|
+
|
|
111
|
+
assert.doesNotThrow(() => checkModulesWebpackConfig(apos.modules, translate));
|
|
112
|
+
|
|
113
|
+
await t.destroy(apos);
|
|
114
|
+
|
|
115
|
+
apos = await t.create({
|
|
116
|
+
root: module,
|
|
117
|
+
modules: badModules
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
assert.throws(() => checkModulesWebpackConfig(apos.modules, translate));
|
|
121
|
+
|
|
122
|
+
await t.destroy(apos);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should get webpack extensions from modules and fill extra bundles', async function () {
|
|
126
|
+
const expectedEntryPointsNames = {
|
|
127
|
+
js: [ 'extra', 'extra2' ],
|
|
128
|
+
css: [ 'extra' ]
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
apos = await t.create({
|
|
132
|
+
root: module,
|
|
133
|
+
modules
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const { extensions, verifiedBundles } = await getWebpackExtensions({
|
|
137
|
+
name: 'src',
|
|
138
|
+
getMetadata: apos.synth.getMetadata,
|
|
139
|
+
modulesToInstantiate: apos.modulesToBeInstantiated()
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
assert(Object.keys(extensions).length === 2);
|
|
143
|
+
assert(!extensions.ext1.resolve.alias.ext1);
|
|
144
|
+
assert(extensions.ext1.resolve.alias.ext1Overriden);
|
|
145
|
+
assert(extensions.ext2.resolve.alias.ext2);
|
|
146
|
+
|
|
147
|
+
assert(Object.keys(verifiedBundles).length === 2);
|
|
148
|
+
|
|
149
|
+
assert(verifiedBundles.extra.js.length === 1);
|
|
150
|
+
assert(verifiedBundles.extra.scss.length === 1);
|
|
151
|
+
|
|
152
|
+
assert(verifiedBundles.extra2.js.length === 1);
|
|
153
|
+
assert(verifiedBundles.extra2.scss.length === 0);
|
|
154
|
+
|
|
155
|
+
const filled = fillExtraBundles(verifiedBundles);
|
|
156
|
+
|
|
157
|
+
filled.js.forEach((name) => {
|
|
158
|
+
assert(expectedEntryPointsNames.js.includes(name));
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
filled.css.forEach((name) => {
|
|
162
|
+
assert(expectedEntryPointsNames.css.includes(name));
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should build the right bundles in dev and prod modes', async function () {
|
|
167
|
+
process.env.NODE_ENV = 'production';
|
|
168
|
+
|
|
169
|
+
await apos.asset.tasks.build.task();
|
|
170
|
+
|
|
171
|
+
const getPath = (p) => `${publicFolderPath}/apos-frontend/` + p;
|
|
172
|
+
const [ releaseId ] = await fs.readdir(getPath('releases'));
|
|
173
|
+
|
|
174
|
+
const checkFileExists = async (p) => fs.pathExists(getPath(p));
|
|
175
|
+
const releasePath = `releases/${releaseId}/default/`;
|
|
176
|
+
|
|
177
|
+
await checkBundlesExists(releasePath, expectedBundlesNames);
|
|
178
|
+
await deleteBuiltFolders(publicFolderPath);
|
|
179
|
+
|
|
180
|
+
process.env.NODE_ENV = 'development';
|
|
181
|
+
|
|
182
|
+
await apos.asset.tasks.build.task();
|
|
183
|
+
await checkBundlesExists('default/', expectedBundlesNames);
|
|
184
|
+
|
|
185
|
+
async function checkBundlesExists (folderPath, fileNames) {
|
|
186
|
+
for (const fileName of fileNames) {
|
|
187
|
+
const extraBundleExists = await checkFileExists(folderPath + fileName);
|
|
188
|
+
assert(extraBundleExists);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should load the right bundles inside the right page', async function () {
|
|
194
|
+
const { _id: homeId } = await apos.page.find(apos.task.getAnonReq(), { level: 0 }).toObject();
|
|
195
|
+
const jar = apos.http.jar();
|
|
196
|
+
|
|
197
|
+
await apos.doc.db.insertMany(pagesToInsert(homeId));
|
|
198
|
+
|
|
199
|
+
const bundlePage = await apos.http.get('/bundle', { jar });
|
|
200
|
+
|
|
201
|
+
assert(bundlePage.includes(getStylesheetMarkup('public-bundle')));
|
|
202
|
+
assert(!bundlePage.includes(getStylesheetMarkup('extra-bundle')));
|
|
203
|
+
|
|
204
|
+
assert(bundlePage.includes(getScriptMarkup('public-module-bundle')));
|
|
205
|
+
assert(!bundlePage.includes(getScriptMarkup('extra-module-bundle')));
|
|
206
|
+
assert(bundlePage.includes(getScriptMarkup('extra2-module-bundle')));
|
|
207
|
+
|
|
208
|
+
const childPage = await apos.http.get('/bundle/child', { jar });
|
|
209
|
+
|
|
210
|
+
assert(childPage.includes(getStylesheetMarkup('public-bundle')));
|
|
211
|
+
assert(childPage.includes(getStylesheetMarkup('extra-bundle')));
|
|
212
|
+
|
|
213
|
+
assert(childPage.includes(getScriptMarkup('public-module-bundle')));
|
|
214
|
+
assert(childPage.includes(getScriptMarkup('extra-module-bundle')));
|
|
215
|
+
assert(!childPage.includes(getScriptMarkup('extra2-module-bundle')));
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should load all the bundles on all pages when the user is logged in', async function () {
|
|
219
|
+
const user = {
|
|
220
|
+
...apos.user.newInstance(),
|
|
221
|
+
title: 'toto',
|
|
222
|
+
username: 'toto',
|
|
223
|
+
password: 'tata',
|
|
224
|
+
email: 'toto@mail.com',
|
|
225
|
+
role: 'admin'
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const jar = apos.http.jar();
|
|
229
|
+
|
|
230
|
+
await apos.user.insert(apos.task.getReq(), user);
|
|
231
|
+
|
|
232
|
+
await apos.http.post(
|
|
233
|
+
'/api/v1/@apostrophecms/login/login',
|
|
234
|
+
{
|
|
235
|
+
method: 'POST',
|
|
236
|
+
body: {
|
|
237
|
+
username: 'toto',
|
|
238
|
+
password: 'tata',
|
|
239
|
+
session: true
|
|
240
|
+
},
|
|
241
|
+
jar
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const homePage = await apos.http.get('/', { jar });
|
|
246
|
+
assert(homePage.match(/logged in/));
|
|
247
|
+
|
|
248
|
+
const bundlePage = await apos.http.get('/bundle', { jar });
|
|
249
|
+
|
|
250
|
+
allBundlesAreIncluded(bundlePage);
|
|
251
|
+
|
|
252
|
+
await t.destroy(apos);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should inject modules and nomodules scripts for extra bundles when es5 enabled', async function () {
|
|
256
|
+
const jar = apos.http.jar();
|
|
257
|
+
|
|
258
|
+
const es5Modules = {
|
|
259
|
+
...modules,
|
|
260
|
+
'@apostrophecms/asset': {
|
|
261
|
+
options: {
|
|
262
|
+
es5: true
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
apos = await t.create({
|
|
268
|
+
root: module,
|
|
269
|
+
modules: es5Modules
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const { _id: homeId } = await apos.page.find(apos.task.getAnonReq(), { level: 0 }).toObject();
|
|
273
|
+
|
|
274
|
+
await apos.doc.db.insertMany(pagesToInsert(homeId));
|
|
275
|
+
|
|
276
|
+
await apos.asset.tasks.build.task();
|
|
277
|
+
|
|
278
|
+
const bundlePage = await apos.http.get('/bundle', { jar });
|
|
279
|
+
|
|
280
|
+
assert(bundlePage.includes(getScriptMarkup('public-module-bundle', 'module')));
|
|
281
|
+
assert(bundlePage.includes(getScriptMarkup('public-nomodule-bundle', 'nomodule')));
|
|
282
|
+
|
|
283
|
+
assert(bundlePage.includes(getScriptMarkup('extra2-module-bundle', 'module')));
|
|
284
|
+
assert(bundlePage.includes(getScriptMarkup('extra2-nomodule-bundle', 'nomodule')));
|
|
285
|
+
});
|
|
24
286
|
});
|
|
287
|
+
|
|
288
|
+
function loadUtils () {
|
|
289
|
+
const publicFolderPath = path.join(process.cwd(), 'test/public');
|
|
290
|
+
|
|
291
|
+
const getScriptMarkup = (file, mod) => {
|
|
292
|
+
const moduleStr = mod === 'module' ? ' type="module"' : ' nomodule';
|
|
293
|
+
|
|
294
|
+
return `<script${mod ? moduleStr : ''} src="/apos-frontend/default/${file}.js"></script>`;
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const getStylesheetMarkup = (file) =>
|
|
298
|
+
`<link href="/apos-frontend/default/${file}.css" rel="stylesheet" />`;
|
|
299
|
+
|
|
300
|
+
const expectedBundlesNames = [ 'extra-module-bundle.js', 'extra2-module-bundle.js', 'extra-bundle.css' ];
|
|
301
|
+
|
|
302
|
+
const deleteBuiltFolders = async (publicPath, deleteAposBuild = false) => {
|
|
303
|
+
await fs.remove(publicPath + '/apos-frontend');
|
|
304
|
+
await fs.remove(publicPath + '/uploads');
|
|
305
|
+
|
|
306
|
+
if (deleteAposBuild) {
|
|
307
|
+
await fs.remove(path.join(process.cwd(), 'test/apos-build'));
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const allBundlesAreIncluded = (page) => {
|
|
312
|
+
assert(page.includes(getStylesheetMarkup('apos-bundle')));
|
|
313
|
+
assert(page.includes(getStylesheetMarkup('extra-bundle')));
|
|
314
|
+
|
|
315
|
+
assert(page.includes(getScriptMarkup('apos-module-bundle')));
|
|
316
|
+
assert(page.includes(getScriptMarkup('extra-module-bundle')));
|
|
317
|
+
assert(page.includes(getScriptMarkup('extra2-module-bundle')));
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
publicFolderPath,
|
|
322
|
+
getScriptMarkup,
|
|
323
|
+
getStylesheetMarkup,
|
|
324
|
+
expectedBundlesNames,
|
|
325
|
+
deleteBuiltFolders,
|
|
326
|
+
allBundlesAreIncluded
|
|
327
|
+
};
|
|
328
|
+
}
|