Skip to content

2494 load extra bundles #3689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
**/vendor/**/*.js
**/blueimp/**/*.js
**/node_modules
**/node_modules
test/public
test/apos-build
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ coverage
/node_modules
/test/node_modules
test/package.json
test/public
test/apos-build

# We do not commit CSS, only LESS, with the exception of a few vendor CSS files we don't have LESS for
*/public/css/*.css
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

* `data-apos-test=""` selectors for certain elements frequently selected in QA tests, such as `data-apos-test="adminBar"`.
* Offer a simple way to set a Cache-Control max-age for Apostrophe page and GET REST API responses for pieces and pages.

* Adds possibility for modules to extend the webpack config as well as to add extra bundles for scss and js.
* Loads the right bundles on the right pages depending on their config and the loaded widgets. Logged-in users have all the bundles on every page.
## 3.15.0 (2022-03-02)

### Adds
Expand Down
89 changes: 55 additions & 34 deletions modules/@apostrophecms/asset/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ const path = require('path');
const express = require('express');
const { stripIndent } = require('common-tags');
const { merge: webpackMerge } = require('webpack-merge');
const cuid = require('cuid');
const {
checkModulesWebpackConfig,
getWebpackExtensions,
fillExtraBundles
fillExtraBundles,
getBundlesNames
} = require('./lib/webpack/utils');

module.exports = {
Expand All @@ -28,13 +30,22 @@ module.exports = {
refreshOnRestart: false
},

init(self) {
async init(self) {
self.restartId = self.apos.util.generateId();
self.iconMap = {
...globalIcons
};
self.configureBuilds();
self.initUploadfs();

const { extensions, verifiedBundles } = await getWebpackExtensions({
getMetadata: self.apos.synth.getMetadata,
modulesToInstantiate: self.apos.modulesToBeInstantiated()
});

self.extraBundles = fillExtraBundles(verifiedBundles);
self.webpackExtensions = extensions;
self.verifiedBundles = verifiedBundles;
},
handlers (self) {
return {
Expand All @@ -56,6 +67,10 @@ module.exports = {
'check-apos-build': true
});
}
},
injectAssetsPlaceholders() {
self.apos.template.prepend('head', '@apostrophecms/asset:stylesheets');
self.apos.template.append('body', '@apostrophecms/asset:scripts');
}
},
'apostrophe:destroy': {
Expand All @@ -67,6 +82,28 @@ module.exports = {
}
};
},
components(self) {
return {
scripts(req, data) {
const placeholder = `[scripts-placeholder:${cuid()}]`;

req.scriptsPlaceholder = placeholder;

return {
placeholder
};
},
stylesheets(req, data) {
const placeholder = `[stylesheets-placeholder:${cuid()}]`;

req.stylesheetsPlaceholder = placeholder;

return {
placeholder
};
}
};
},
tasks(self) {
return {
build: {
Expand All @@ -78,7 +115,6 @@ module.exports = {
const buildDir = `${self.apos.rootDir}/apos-build/${namespace}`;
const bundleDir = `${self.apos.rootDir}/public/apos-frontend/${namespace}`;
const modulesToInstantiate = self.apos.modulesToBeInstantiated();
const extraBundles = [];

// Don't clutter up with previous builds.
await fs.remove(buildDir);
Expand Down Expand Up @@ -133,8 +169,7 @@ module.exports = {
await fs.mkdirp(bundleDir);
await build({
name,
options,
bundles: extraBundles
options
});
}
}
Expand All @@ -153,7 +188,12 @@ module.exports = {
cwd: bundleDir,
mark: true
}).filter(match => !match.endsWith('/'));
deployFiles = [ ...deployFiles, ...publicAssets, ...extraBundles ];
deployFiles = [
...deployFiles,
...publicAssets,
...getBundlesNames(self.extraBundles, self.options.es5)
];

await deploy(deployFiles);

if (process.env.APOS_BUNDLE_ANALYZER) {
Expand Down Expand Up @@ -198,7 +238,7 @@ module.exports = {
}

async function build({
name, bundles, options
name, options
}) {
self.apos.util.log(req.t('apostrophe:assetTypeBuilding', {
label: req.t(options.label)
Expand Down Expand Up @@ -270,24 +310,16 @@ module.exports = {
const webpack = Promise.promisify(webpackModule);
const webpackBaseConfig = require(`./lib/webpack/${name}/webpack.config`);

const { extensions, verifiedBundles } = await getWebpackExtensions({
name,
getMetadata: self.apos.synth.getMetadata,
modulesToInstantiate
});

verifiedBundles && fillExtraBundles(verifiedBundles, bundles);

const webpackInstanceConfig = webpackBaseConfig({
importFile,
modulesDir,
outputPath: bundleDir,
outputFilename,
bundles: verifiedBundles
bundles: self.verifiedBundles
}, self.apos);

const webpackInstanceConfigMerged = extensions
? webpackMerge(webpackInstanceConfig, ...Object.values(extensions))
const webpackInstanceConfigMerged = self.webpackExtensions
? webpackMerge(webpackInstanceConfig, ...Object.values(self.webpackExtensions))
: webpackInstanceConfig;

const result = await webpack(webpackInstanceConfigMerged);
Expand Down Expand Up @@ -410,8 +442,9 @@ module.exports = {
};

const filesContent = Object.entries(self.builds)
.filter(([ _, options ]) => filterBuilds(options)
).map(([ name ]) => {
.filter(([ _, options ]) => filterBuilds(options))
.map(([ name ]) => {

const file = `${bundleDir}/${name}-build.${fileExt}`;
const readFile = (n, f) => `/* BUILD: ${n} */\n${fs.readFileSync(f, 'utf8')}`;

Expand Down Expand Up @@ -594,22 +627,10 @@ module.exports = {
}
},
stylesheetsHelper(when) {
const base = self.getAssetBaseUrl();
const bundle = `<link href="${base}/${when}-bundle.css" rel="stylesheet" />`;
return self.apos.template.safe(bundle);
return '';
},
scriptsHelper(when) {
const base = self.getAssetBaseUrl();
if (self.options.es5) {
return self.apos.template.safe(stripIndent`
<script nomodule src="${base}/${when}-nomodule-bundle.js"></script>
<script type="module" src="${base}/${when}-module-bundle.js"></script>
`);
} else {
return self.apos.template.safe(stripIndent`
<script src="${base}/${when}-module-bundle.js"></script>
`);
}
return '';
},
shouldRefreshOnRestart() {
return self.options.refreshOnRestart && (process.env.NODE_ENV !== 'production');
Expand Down
27 changes: 20 additions & 7 deletions modules/@apostrophecms/asset/lib/webpack/src/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,24 @@ module.exports = ({
};

function formatBundles (bundles, mainBundleName) {
return bundles.reduce((acc, { bundleName, paths }) => ({
...acc,
[bundleName]: {
import: paths,
dependOn: mainBundleName
}
}), {});
return bundles.reduce((acc, { bundleName, paths }) => {
const jsPaths = paths.filter((p) => p.endsWith('.js'));
const scssPaths = paths.filter((p) => p.endsWith('.scss'));

return {
...acc,
...jsPaths.length && {
[`${bundleName}-module-bundle`]: {
import: jsPaths,
dependOn: mainBundleName
}
},
...scssPaths.length && {
[`${bundleName}-bundle`]: {
import: scssPaths,
dependOn: mainBundleName
}
}
};
}, {});
}
70 changes: 55 additions & 15 deletions modules/@apostrophecms/asset/lib/webpack/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const fs = require('fs-extra');
module.exports = {
checkModulesWebpackConfig(modules, t) {
const allowedProperties = [ 'extensions', 'bundles' ];

for (const mod of Object.values(modules)) {
const webpackConfig = mod.__meta.webpack[mod.__meta.name];

Expand All @@ -23,16 +22,31 @@ module.exports = {

throw new Error(error);
}

if (webpackConfig && webpackConfig.bundles) {
const bundles = Object.values(webpackConfig.bundles);

bundles.forEach(bundle => {
const bundleProps = Object.keys(bundle);
if (
bundleProps.length > 1 ||
(bundleProps.length === 1 && !bundle.templates) ||
(bundle.templates && !Array.isArray(bundle.templates))
) {
const error = t('apostrophe:assetWebpackBundlesWarning', {
module: mod.__meta.name
});

throw new Error(error);
}
});
}
}
},

async getWebpackExtensions ({
name, getMetadata, modulesToInstantiate
getMetadata, modulesToInstantiate
}) {
if (name !== 'src') {
return {};
}

const modulesMeta = modulesToInstantiate
.map((name) => getMetadata(name));

Expand All @@ -48,17 +62,43 @@ module.exports = {
};
},

fillExtraBundles (verifiedBundles, bundles) {
const bundlesPaths = verifiedBundles
.reduce((acc, { paths }) => ([
...acc,
...paths.map((p) => p.substr(p.lastIndexOf('/') + 1)
.replace(/\.scss$/, '.css'))
]), []);
fillExtraBundles (verifiedBundles = []) {
const getFileName = (p) => p.substr(p.lastIndexOf('/') + 1)
.replace(/\.(js|scss)$/, '');

bundlesPaths.forEach(bundle => {
bundles.push(bundle);
return verifiedBundles.reduce((acc, { paths }) => {
return {
js: [
...acc.js,
...paths.filter((p) => p.endsWith('.js')).map((p) => getFileName(p))
],
css: [
...acc.css,
...paths.filter((p) => p.endsWith('.scss')).map((p) => getFileName(p))
]
};
}, {
js: [],
css: []
});
},

getBundlesNames (bundles, es5 = false) {
return Object.entries(bundles).reduce((acc, [ ext, bundlesNames ]) => {
const nameExtension = ext === 'css'
? '-bundle'
: '-module-bundle';

const es5Bundles = es5 && ext === 'js'
? bundlesNames.map((name) => `${name}-nomodule-bundle.${ext}`)
: [];

return [
...acc,
...bundlesNames.map((name) => `${name}${nameExtension}.${ext}`),
...es5Bundles
];
}, []);
}
};

Expand Down
1 change: 1 addition & 0 deletions modules/@apostrophecms/asset/views/scripts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ data.placeholder }}
1 change: 1 addition & 0 deletions modules/@apostrophecms/asset/views/stylesheets.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ data.placeholder }}
1 change: 1 addition & 0 deletions modules/@apostrophecms/i18n/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"assetTypeBuildComplete": "👍 {{ label }} is complete!",
"assetTypeBuilding": "🧑‍💻 Building the {{ label }}...",
"assetWebpackConfigWarning": "⚠️ In the module {{ module }}, your webpack config is incorrect. It must be an object and should contain only two properties extensions and bundles.",
"assetWebpackBundlesWarning": "⚠️ In the module {{ module }} your webpack config is incorrect. Each bundle can only have one property 'templates' that must be an array of strings.",
"back": "Back",
"backToHome": "Back to Home",
"basics": "Basics",
Expand Down
19 changes: 14 additions & 5 deletions modules/@apostrophecms/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ module.exports = {
},
methods(self) {
return {
...require('./lib/bundlesLoader')(self),

// Add helpers in the namespace for a particular module.
// They will be visible in nunjucks at
Expand Down Expand Up @@ -630,8 +631,6 @@ module.exports = {
// async function.

async renderPageForModule(req, template, data, module) {

let content;
let scene = req.user ? 'apos' : 'public';
if (req.scene) {
scene = req.scene;
Expand Down Expand Up @@ -698,15 +697,25 @@ module.exports = {
}

try {
content = await module.render(req, template, args);
const content = await module.render(req, template, args);

const filledContent = self.insertBundlesMarkup({
page: req.data.bestPage,
scene,
template,
content,
scriptsPlaceholder: req.scriptsPlaceholder,
stylesheetsPlaceholder: req.stylesheetsPlaceholder,
widgetsBundles: req.widgetsBundles
});

return filledContent;
} catch (e) {
// The page template threw an exception. Log where it
// occurred for easier debugging
return error(e);
}

return content;

function error(e) {
self.logError(req, e);
req.statusCode = 500;
Expand Down
Loading