Skip to content

Commit

Permalink
client side router optimization setting for build
Browse files Browse the repository at this point in the history
  • Loading branch information
thescientist13 committed Mar 23, 2021
1 parent fba89da commit aafb10f
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 11 deletions.
1 change: 1 addition & 0 deletions greenwood.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const FAVICON_HREF = '/assets/favicon.ico';

module.exports = {
workspace: path.join(__dirname, 'www'),
optimization: 'mpa',
title: 'Greenwood',
meta: [
{ name: 'description', content: META_DESCRIPTION },
Expand Down
14 changes: 12 additions & 2 deletions packages/cli/src/config/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const postcss = require('postcss');
const postcssImport = require('postcss-import');
const replace = require('@rollup/plugin-replace');
const { terser } = require('rollup-plugin-terser');

const tokenSuffix = 'scratch';
const tokenNodeModules = 'node_modules/';

Expand Down Expand Up @@ -306,8 +305,19 @@ function greenwoodHtmlPlugin(compilation) {
for (const innerBundleId of Object.keys(bundles)) {
const { src } = parsedAttributes;
const facadeModuleId = bundles[innerBundleId].facadeModuleId;
const pathToMatch = src.replace('../', '').replace('./', '');
let pathToMatch = src.replace('../', '').replace('./', '');

if (pathToMatch.indexOf(tokenNodeModules) >= 0) {
pathToMatch = pathToMatch.replace(`/${tokenNodeModules}`, '');

const pathToMatchPieces = pathToMatch.split('/');

pathToMatch = pathToMatch.replace(tokenNodeModules, '');
pathToMatch = pathToMatch.replace(`${pathToMatchPieces[0]}/`, '');
}
console.debug('facadeModuleId', facadeModuleId);
console.debug('pathToMatch', pathToMatch);
console.debug('*******************************');
if (facadeModuleId && facadeModuleId.indexOf(pathToMatch) > 0) {
newHtml = newHtml.replace(src, `/${innerBundleId}`);
}
Expand Down
38 changes: 38 additions & 0 deletions packages/cli/src/lib/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable no-underscore-dangle */
document.addEventListener('click', function(e) {
e.preventDefault();

console.debug('linked clicked was...', e.path[0].href);
const target = e.path[0];
const route = target.href.replace(window.location.origin, '');
const routerOutlet = Array.from(document.getElementsByTagName('greenwood-route')).filter(outlet => {
return outlet.getAttribute('data-route') === route;
})[0];

console.debug('routerOutlet', routerOutlet);

if (routerOutlet.getAttribute('data-template') === window.__greenwood.currentTemplate) {
window.__greenwood.currentTemplate = routerOutlet.getAttribute('data-template');
routerOutlet.loadRoute();
} else {
console.debug('new template detected, should do a hard reload');
window.location.href = target;
}
});

class RouteComponent extends HTMLElement {
loadRoute() {
console.debug('load route ->', this.getAttribute('data-route'));
console.debug('with bundle ->', this.getAttribute('data-key'));
fetch(this.getAttribute('data-key'))
.then(res => res.text())
.then((response) => {
document.getElementsByTagName('router-outlet')[0].innerHTML = response;
});
}
}

class RouterOutletComponent extends HTMLElement { }

customElements.define('greenwood-route', RouteComponent);
customElements.define('router-outlet', RouterOutletComponent);
18 changes: 9 additions & 9 deletions packages/cli/src/lifecycles/config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const fs = require('fs');
const path = require('path');

// TODO const optimizations = ['strict', 'spa'];
const optimizations = ['default', 'mpa']; // TOOD implement none, strict

let defaultConfig = {
workspace: path.join(process.cwd(), 'src'),
devServer: {
port: 1984
},
optimization: '',
optimization: 'default',
title: 'My App',
meta: [],
plugins: [],
Expand All @@ -23,7 +24,7 @@ module.exports = readAndMergeConfig = async() => {

if (fs.existsSync(path.join(process.cwd(), 'greenwood.config.js'))) {
const userCfgFile = require(path.join(process.cwd(), 'greenwood.config.js'));
const { workspace, devServer, title, markdown, meta, plugins } = userCfgFile;
const { workspace, devServer, title, markdown, meta, optimization, plugins } = userCfgFile;

// workspace validation
if (workspace) {
Expand Down Expand Up @@ -61,12 +62,11 @@ module.exports = readAndMergeConfig = async() => {
customConfig.meta = meta;
}

// TODO
// if (typeof optimization === 'string' && optimizations.indexOf(optimization.toLowerCase()) >= 0) {
// customConfig.optimization = optimization;
// } else if (optimization) {
// reject(`Error: provided optimization "${optimization}" is not supported. Please use one of: ${optimizations.join(', ')}.`);
// }
if (typeof optimization === 'string' && optimizations.indexOf(optimization.toLowerCase()) >= 0) {
customConfig.optimization = optimization;
} else if (optimization) {
reject(`Error: provided optimization "${optimization}" is not supported. Please use one of: ${optimizations.join(', ')}.`);
}

if (plugins && plugins.length > 0) {
const types = ['resource', 'rollup', 'server'];
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/lifecycles/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ const BrowserRunner = require('../lib/browser');
const fs = require('fs');
const path = require('path');
const pluginResourceStandardHtml = require('../plugins/resource/plugin-standard-html');
const pluginOptimizationMpa = require('../plugins/resource/plugin-optimization-mpa');

module.exports = serializeCompilation = async (compilation) => {
const compilationCopy = Object.assign({}, compilation);
const browserRunner = new BrowserRunner();
const optimizeResources = [
pluginResourceStandardHtml.provider(compilationCopy),
pluginOptimizationMpa()[0].provider(compilationCopy),
...compilation.config.plugins.filter((plugin) => {
const provider = plugin.provider(compilationCopy);

Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/lifecycles/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const path = require('path');
const Koa = require('koa');

const pluginNodeModules = require('../plugins/resource/plugin-node-modules');
const pluginResourceOptimizationMpa = require('../plugins/resource/plugin-optimization-mpa');
const pluginResourceStandardCss = require('../plugins/resource/plugin-standard-css');
const pluginResourceStandardFont = require('../plugins/resource/plugin-standard-font');
const pluginResourceStandardHtml = require('../plugins/resource/plugin-standard-html');
Expand All @@ -26,6 +27,7 @@ function getDevServer(compilation) {
pluginResourceStandardImage.provider(compilationCopy),
pluginResourceStandardJavaScript.provider(compilationCopy),
pluginResourceStandardJson.provider(compilationCopy),
pluginResourceOptimizationMpa()[0].provider(compilationCopy),

// custom user resource plugins
...compilation.config.plugins.filter((plugin) => {
Expand Down
146 changes: 146 additions & 0 deletions packages/cli/src/plugins/resource/plugin-optimization-mpa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
*
* Manages web standard resource related operations for JavaScript.
* This is a Greenwood default plugin.
*
*/
const fs = require('fs');
const path = require('path');
const { ResourceInterface } = require('../../lib/resource-interface');
// const rollupPluginAlias = require('@rollup/plugin-alias');

class OptimizationMPAResource extends ResourceInterface {
constructor(compilation, options) {
super(compilation, options);
this.extensions = ['.html'];
this.contentType = 'text/html';
this.libPath = '@greenwood/router/router.js';
}

// TODO make this work using this.libPath
async shouldResolve(url) {
return Promise.resolve(url.indexOf(this.libPath) >= 0);
}

async resolve() {
return new Promise(async (resolve, reject) => {
try {
const routerUrl = path.join(__dirname, '../../', 'lib/router.js');

resolve(routerUrl);
} catch (e) {
reject(e);
}
});
}

// TODO add support for running in development?
// async shouldIntercept(url, body, headers) {
// return Promise.resolve(this.compilation.config.optimization === 'mpa' && headers.request.accept.indexOf('text/html') >= 0);
// }

// async intercept(url, body) {
// return new Promise(async (resolve, reject) => {
// try {
// // es-modules-shims breaks on dangling commas in an importMap :/
// const danglingComma = body.indexOf('"imports": {}') > 0
// ? ''
// : ',';
// const shimmedBody = body.replace('"imports": {', `
// "imports": {
// "@greenwood/cli/lib/router": "/node_modules/@greenwood/cli/lib/router.js"${danglingComma}
// `);

// resolve({ body: shimmedBody });
// } catch (e) {
// reject(e);
// }
// });
// }

async shouldOptimize(url) {
return Promise.resolve(path.extname(url) === '.html' && this.compilation.config.optimization === 'mpa');
}

async optimize(url, body) {
return new Promise(async (resolve, reject) => {
try {
let currentTemplate;
const { projectDirectory, scratchDir, outputDir } = this.compilation.context;
const bodyContents = body.match(/<body>(.*)<\/body>/s)[0].replace('<body>', '').replace('</body>', '');
const outputBundlePath = `${outputDir}/_routes${url.replace(projectDirectory, '')}`
.replace('.greenwood/', '')
.replace('//', '/');

const routeTags = this.compilation.graph.map((page) => {
const template = path.extname(page.filename) === '.html'
? page.route
: page.template;
const key = page.route === '/'
? ''
: page.route.slice(0, page.route.lastIndexOf('/'));

if (url.replace(scratchDir, '') === `${page.route}index.html`) {
currentTemplate = template;
}
return `
<greenwood-route data-route="${page.route}" data-template="${template}" data-key="/_routes${key}/index.html"></greenwood-route>
`;
});

if (!fs.existsSync(path.dirname(outputBundlePath))) {
fs.mkdirSync(path.dirname(outputBundlePath), {
recursive: true
});
}

await fs.promises.writeFile(outputBundlePath, bodyContents);

// TODO this gets swalloed by Rollup?
// <script type="module" src="/node_modules/@greenw">
// import "@greenwood/cli/lib/router";
// </script>\n
body = body.replace('</head>', `
<script type="module" src="/node_modules/@greenwood/cli/src/lib/router.js"></script>\n
<script>
window.__greenwood = window.__greenwood || {};
window.__greenwood.currentTemplate = "${currentTemplate}";
</script>
</head>
`).replace(/<body>(.*)<\/body>/s, `
<body>\n
<router-outlet>
${bodyContents}\n
</router-outlet>
${routeTags.join('\n')}
</body>
`);

resolve(body);
} catch (e) {
reject(e);
}
});
}
}

module.exports = (options = {}) => {
return [{
type: 'resource',
name: 'plugin-optimization-mpa',
provider: (compilation) => new OptimizationMPAResource(compilation, options)
// }, {
// type: 'rollup',
// name: 'plugin-optimization-mpa:rollup',
// provider: () => [
// rollupPluginAlias({
// entries: [
// { find: '@greenwood/cli/lib/router', replacement: '/node_modules/@greenwood/cli/lib/router.js' }
// ]
// })
// ]
}];
};

0 comments on commit aafb10f

Please sign in to comment.