Skip to content

Commit

Permalink
task/issue 356 Extendable App Templates (#382)
Browse files Browse the repository at this point in the history
* task: extend app-template

* fix: lint issues

* test: fix broken tests

* docs: update documentation with new stripped down app-template info

* fix: cleanup

* fix: make requirements more clear

* fix: formatting

* fix: conventional file names/paths

* test: fix example

* fix: change base-app to app-root

* fix: content wrapper prefix

* test: update tests

Co-authored-by: hutchgrant <[email protected]>
Co-authored-by: Owen Buckley <[email protected]>
  • Loading branch information
3 people authored Jul 22, 2020
1 parent 78190a4 commit 7bbdb17
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 250 deletions.
3 changes: 2 additions & 1 deletion packages/cli/src/config/webpack.config.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ module.exports = ({ config, context }) => {
resolve: {
extensions: ['.js', '.json', '.gql', '.graphql'],
alias: {
'@greenwood/cli/data': context.dataDir
'@greenwood/cli/data': context.dataDir,
'@greenwood/cli/templates/app-template': path.join(context.scratchDir, 'app', 'app-template.js')
}
},

Expand Down
20 changes: 19 additions & 1 deletion packages/cli/src/lifecycles/scaffold.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const writeRoutes = async(compilation) => {
const appDir = path.join(compilation.context.scratchDir, 'app');

await fs.ensureDir(appDir);
await fs.writeFile(path.join(appDir, './app.js'), result);
await fs.writeFile(path.join(appDir, './app-template.js'), result);

resolve();
} catch (err) {
Expand All @@ -98,6 +98,21 @@ const writeRoutes = async(compilation) => {
});
};

const writeBaseAppTemplate = async({ context }) => {
return new Promise(async (resolve, reject) => {
try {
let data = await fs.readFile(path.join(__dirname, '../templates/', 'base-template.js'), 'utf8');
const appDir = path.join(context.scratchDir, 'app');

await fs.ensureDir(appDir);
await fs.writeFile(path.join(appDir, './app.js'), data);
resolve();
} catch (err) {
reject(err);
}
});
};

const setupIndex = async({ context }) => {
return new Promise(async (resolve, reject) => {
try {
Expand Down Expand Up @@ -125,6 +140,9 @@ module.exports = generateScaffolding = async (compilation) => {
console.log('Writing Lit routes...');
await writeRoutes(compilation);

console.log('Write Base App Template...');
await writeBaseAppTemplate(compilation);

console.log('setup index page and html');
await setupIndex(compilation);

Expand Down
94 changes: 3 additions & 91 deletions packages/cli/src/templates/app-template.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,13 @@
import { html, LitElement } from 'lit-element';
import { connectRouter } from 'lit-redux-router';
import { applyMiddleware, createStore, compose as origCompose, combineReducers } from 'redux';
import { lazyReducerEnhancer } from 'pwa-helpers/lazy-reducer-enhancer.js';
import thunk from 'redux-thunk';
import client from '@greenwood/cli/data/client';
import ConfigQuery from '@greenwood/cli/data/queries/config';
import GraphQuery from '@greenwood/cli/data/queries/graph';

// eslint-disable-next-line no-underscore-dangle
const compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || origCompose;

const store = createStore((state) => state,
compose(lazyReducerEnhancer(combineReducers), applyMiddleware(thunk))
);

import '../index/index';

connectRouter(store);

class AppComponent extends LitElement {

async connectedCallback() {
super.connectedCallback();
const route = window.location.pathname;
const response = await Promise.all([
await client.query({
query: ConfigQuery
}),
await client.query({
query: GraphQuery
})
]);
const { config } = response[0].data;
const currentPage = response[1].data.graph.filter((page) => {
return route === page.link;
})[0];

const currentPageTitleSuffix = !currentPage || currentPage.link === '/'
? ''
: ` - ${currentPage.title}`;
const fullTitle = `${config.title}${currentPageTitleSuffix}`;

this.setDocumentTitle(fullTitle);
this.setMeta(config.meta, currentPage);
}

setDocumentTitle(title = '') {
const head = document.head;
const titleElement = head.getElementsByTagName('title')[0];

titleElement.innerHTML = title;
}

setMeta(meta = [], currentPage = {}) {
let header = document.head;

meta.forEach(metaItem => {
const metaType = metaItem.rel // type of meta
? 'rel'
: metaItem.name
? 'name'
: 'property';
const metaTypeValue = metaItem[metaType]; // value of the meta
let meta = document.createElement('meta');

if (metaType === 'rel') {
// change to a <link> tag instead
meta = document.createElement('link');

meta.setAttribute('rel', metaTypeValue);
meta.setAttribute('href', metaItem.href);
} else {
const metaContent = metaItem.property === 'og:url'
? `${metaItem.content}${currentPage.link}`
: metaItem.content;

meta.setAttribute(metaType, metaItem[metaType]);
meta.setAttribute('content', metaContent);
}

const oldmeta = header.querySelector(`[${metaType}="${metaTypeValue}"]`);

// rehydration
if (oldmeta) {
header.replaceChild(meta, oldmeta);
} else {
header.appendChild(meta);
}
});
}

render() {
return html`
MYROUTES
<lit-route><h1>404 Not found</h1></lit-route>
MYROUTES
<lit-route><h1>404 Not found</h1></lit-route>
`;
}
}

customElements.define('eve-app', AppComponent);
customElements.define('eve-app', AppComponent);
104 changes: 104 additions & 0 deletions packages/cli/src/templates/base-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { html, LitElement } from 'lit-element';
import { connectRouter } from 'lit-redux-router';
import { applyMiddleware, createStore, compose as origCompose, combineReducers } from 'redux';
import { lazyReducerEnhancer } from 'pwa-helpers/lazy-reducer-enhancer.js';
import thunk from 'redux-thunk';
import client from '@greenwood/cli/data/client';
import ConfigQuery from '@greenwood/cli/data/queries/config';
import GraphQuery from '@greenwood/cli/data/queries/graph';
import '@greenwood/cli/templates/app-template';
// eslint-disable-next-line no-underscore-dangle
const compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || origCompose;

const store = createStore((state) => state,
compose(lazyReducerEnhancer(combineReducers), applyMiddleware(thunk))
);

import '../index/index';

connectRouter(store);

class BaseAppComponent extends LitElement {

async connectedCallback() {
super.connectedCallback();
const route = window.location.pathname;
const response = await Promise.all([
await client.query({
query: ConfigQuery
}),
await client.query({
query: GraphQuery
})
]);
const { config } = response[0].data;
const currentPage = response[1].data.graph.filter((page) => {
return route === page.link;
})[0];

const currentPageTitleSuffix = !currentPage || currentPage.link === '/'
? ''
: ` - ${currentPage.title}`;
const fullTitle = `${config.title}${currentPageTitleSuffix}`;

this.setDocumentTitle(fullTitle);
this.setMeta(config.meta, currentPage);
}

setDocumentTitle(title = 'test') {
const head = document.head;
const titleElement = head.getElementsByTagName('title')[0];

titleElement.innerHTML = title;
}

setMeta(meta = [], currentPage = {}) {
let header = document.head;

meta.forEach(metaItem => {
const metaType = metaItem.rel // type of meta
? 'rel'
: metaItem.name
? 'name'
: 'property';
const metaTypeValue = metaItem[metaType]; // value of the meta
let meta = document.createElement('meta');

if (metaType === 'rel') {
// change to a <link> tag instead
meta = document.createElement('link');

meta.setAttribute('rel', metaTypeValue);
meta.setAttribute('href', metaItem.href);
} else {
const metaContent = metaItem.property === 'og:url'
? `${metaItem.content}${currentPage.link}`
: metaItem.content;

meta.setAttribute(metaType, metaItem[metaType]);
meta.setAttribute('content', metaContent);
}

const oldmeta = header.querySelector(`[${metaType}="${metaTypeValue}"]`);

// rehydration
if (oldmeta) {
header.replaceChild(meta, oldmeta);
} else {
header.appendChild(meta);
}
});
}

createRenderRoot() {
return this;
}

render() {
return html`
<eve-app></eve-app>
`;
}
}

customElements.define('app-root', BaseAppComponent);
2 changes: 1 addition & 1 deletion packages/cli/src/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<body>

<eve-app></eve-app>
<app-root></app-root>

</body>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ describe('Build Greenwood With: ', function() {
dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, './index.html'));
});

it('should not contain any components within eve-app', function() {
it('should not contain any components within app-root', function() {
// prove that our custom broken babel config is being used
const outlet = dom.window.document.querySelector('body > eve-app').innerHTML;
const outlet = dom.window.document.querySelector('body > app-root').innerHTML;
expect(outlet).to.equal('');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ module.exports = ({ config, context }) => {
resolve: {
extensions: ['.js', '.json', '.gql', '.graphql'],
alias: {
'@greenwood/cli/data': path.join(__dirname, '../../..', './src', './data')
'@greenwood/cli/data': path.join(__dirname, '../../..', './src', './data'),
'@greenwood/cli/templates/app-template': path.join(context.scratchDir, 'app', 'app-template.js')
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe('Build Greenwood With: ', function() {
});

it('should have a router outlet tag in the <body>', function() {
const outlet = dom.window.document.querySelectorAll('body eve-app');
const outlet = dom.window.document.querySelectorAll('body app-root');

expect(outlet.length).to.be.equal(1);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,11 @@
import { html, LitElement } from 'lit-element';
import { connectRouter } from 'lit-redux-router';
import { applyMiddleware, createStore, compose as origCompose, combineReducers } from 'redux';
import { lazyReducerEnhancer } from 'pwa-helpers/lazy-reducer-enhancer.js';
import thunk from 'redux-thunk';
import client from '@greenwood/cli/data/client';
import ConfigQuery from '@greenwood/cli/data/queries/config';

// eslint-disable-next-line no-underscore-dangle
const compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || origCompose;

// eslint-disable-next-line
const store = createStore(
(state, action) => state, // eslint-disable-line
compose(lazyReducerEnhancer(combineReducers), applyMiddleware(thunk)));

import '../index/index';

connectRouter(store);

class AppComponent extends LitElement {

async connectedCallback() {
super.connectedCallback();

const response = await client.query({
query: ConfigQuery
});
const { config } = response.data;

this.setDocoumentTitle(config.title);
}

setDocoumentTitle(title) {
const head = document.head;
const titleElement = head.getElementsByTagName('title')[0];

titleElement.innerHTML = title;
}

render() {
return html`
MYROUTES
<p id="custom-app-template">My Custom App Template</p>
MYROUTES
<p id="custom-app-template">My Custom App Template</p>
`;
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/smoke-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function defaultIndex(label) {
});

it('should have one <script> tag in the <body> for the main bundle', function() {
const scriptTags = dom.window.document.querySelectorAll('body eve-app ~ script');
const scriptTags = dom.window.document.querySelectorAll('body app-root ~ script');
const bundledScript = Array.prototype.slice.call(scriptTags).filter(script => {
const src = script.src.replace('file:///', '');

Expand Down
Loading

0 comments on commit 7bbdb17

Please sign in to comment.