Skip to content

Commit

Permalink
Make front-matter label var optional (#58)
Browse files Browse the repository at this point in the history
* fix: updating to wc-markdown-loader 0.0.7 removing need for label var

* fix: removing all front-matter from default template

* fix: remove debug output and update to wc-markdown-loader 0.0.8 refactored

* docs: update readme for optional front-matter

* test: adding custom front-matter override app and tests

* test: reverting default template front-matter, updating tests

* fix: updating wc-markdown-loader package depend, removing comment from test

* fix: updating yarn.lock

* test: modify user workspace tests to not use label fm var, add single page for testing override fm var

* test: remove custom-fm fixture entirely

* test: remove template var from all previous mock-app pages

* fix: remove unnecessary code block fencing
  • Loading branch information
hutchgrant authored and thescientist13 committed Apr 28, 2019
1 parent 2ad417d commit f96db0d
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 67 deletions.
89 changes: 62 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ $ greenwood
```

Fun! But naturally you'll want to make your own pages. So create a folder called _src/pages/_ and create a page called _index.md_.
```shell
---
label: 'hello'
---

```md
# Helloworld
```

Expand Down Expand Up @@ -47,39 +43,77 @@ Your project will generally have a structure like this:
> Customize
### Creating A Page
Here's a an example of a page

Pages should be placed in your `src/pages/` directory. Page filenames will become the page's generated path. e.g.

Here's a an example of a `src/pages/mypage.md`
```md
### Hello World

This is an example page built by Greenwood. Make your own in _src/pages_!
```

Will accessible at http://localhost:8000/mypage

You can nest directories in your `src/pages` directory which will also be used for the final URL.

e.g. a markdown file at `src/pages/myblog/mycategory/index.md` will be accessible at http://localhost:8000/myblog/mycategory

Another example a markdown file at `src/pages/myblog/mycategory/mypage.md` will be accessible at http://localhost:8000/myblog/mycategory/mypage

You can also create [custom templates](#front-matter-template) to style and layout each page. As well as [customize the overall app template](#app-template)

## Advanced Markdown

You can add front-matter variables to the top, such as label, template, imports, as well as render components and html within each md file.

### Front-Matter Label

By default, a randomly generated export name will be created. `label` front-matter variable is completely optional.

`label` front-matter variable will set the name of the exported md built web component element, within a default page template.

e.g. example below would output `<eve-hello></eve-hello>` with a child of `<wc-md-hello></wc-md-hello>` element containing the markdown


```md
---
label: 'hello'
template: 'page'
---

### Hello World

This is an example page built by Greenwood. Make your own in _src/pages_!
This is an example page built by Greenwood. Make your own in src/pages!

```

And a page template
```javascript
import { html, LitElement } from 'lit-element';

class index extends LitElement {
render() {
return html`
<h1>Greenwood</h1>
<div>
This is the home page built by Greenwood. Make your own pages in <i>src/pages/index.js</i>!
</div>
`;
}
}

customElements.define('home-page', index);
### Front-Matter Template

You can also have your md file compiled within a custom page template. By default, each md file is automatically placed in a default(included) `page-template.js` component and exported with a generated/set label name.

e.g. example below `<eve-hello></eve-hello>` (all template element labels are prepended with `eve-`).

You can add custom templates by specifying the `template` front-matter variable.

The `template` variable string value will be appended with `-template.js` and is expected to be the an accessibile filename from within your `src/templates` directory.

e.g. `template: 'guides'` will use a `src/template/guides-template.js` file.

[See Page Template section](#page-template) below for an example `page-template.js` file.

```md
---
label: 'hello'
template: 'guides'
---
### Hello World

This is an example page built by Greenwood. Make your own in src/pages!

```

## Advanced Markdown
### Front-Matter Render

You can also render custom html such as a custom style or even a component within your markdown page using `imports` in your front-matter variables at top, as well as utilizing the `render` code block e.g.
You can also render custom html such as a custom style or even a component within your markdown page using `imports` in your front-matter variables, as well as utilizing the `render` code block e.g.

````md
---
Expand All @@ -99,6 +133,7 @@ This is an example page built by Greenwood. Make your own in src/pages!
<my-component></my-component>
```
````

## API
Here are some of the features and capabiliites of Greenwood.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"rimraf": "^2.6.3",
"wc-markdown-loader": "^0.0.6",
"wc-markdown-loader": "^0.0.8",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1",
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/config/webpack.config.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const mapUserWorkspaceDirectory = (userPath) => {
);
};

module.exports = (context) => {
module.exports = (context, graph) => {
// dynamically map all the user's workspace directories for resolution by webpack
// this essentially helps us keep watch over changes from the user, and greenwood's build pipeline
const mappedUserDirectoriesForWebpack = getUserWorkspaceDirectories(context.userWorkspace).map(mapUserWorkspaceDirectory);
Expand Down Expand Up @@ -63,10 +63,10 @@ module.exports = (context) => {
}
}, {
test: /\.md$/,
loaders: [
'babel-loader',
'wc-markdown-loader'
]
loader: 'wc-markdown-loader',
options: {
graph
}
}, {
test: /\.css$/,
loaders: [
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/config/webpack.config.develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const rebuild = async() => {
}
};

module.exports = (context) => {
const configWithContext = commonConfig(context);
module.exports = ({ context, graph }) => {
const configWithContext = commonConfig(context, graph);
const publicPath = configWithContext.output.publicPath;

return webpackMerge(configWithContext, {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ const path = require('path');
const webpackMerge = require('webpack-merge');
const commonConfig = require(path.join(__dirname, '..', './config/webpack.config.common.js'));

module.exports = (context) => {
const configWithContext = commonConfig(context);
module.exports = ({ context, graph }) => {
const configWithContext = commonConfig(context, graph);

return webpackMerge(configWithContext, {

Expand Down
21 changes: 19 additions & 2 deletions packages/cli/lib/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ const createGraphFromPages = async (pagesDir) => {

// determine if this is an index file, if so set route to '/'
let route = fileRoute === '/index' ? '/' : fileRoute;

// check if additional nested directories
if (seperatorIndex > 0) {
// get all remaining nested page directories
completeNestedPath = subDir.substring(0, seperatorIndex);

// set route to the nested pages path and file name(without extension)
route = completeNestedPath + route;
mdFile = `./${completeNestedPath}${fileRoute}.md`;
Expand All @@ -62,6 +62,9 @@ const createGraphFromPages = async (pagesDir) => {
relativeExpectedPath = `'../${fileName}/${fileName}.js'`;
}

// generate a random element name
label = label || generateRandomElementLabel(6);

/*
* Variable Definitions
*----------------------
Expand All @@ -73,6 +76,7 @@ const createGraphFromPages = async (pagesDir) => {
* fileName: file name without extension/path, so that it can be copied to scratch dir with same name
* relativeExpectedPath: relative import path for generated component within a list.js file to later be
* imported into app.js root component
* elementLabel: the element name for the generated md page e.g. <wc-md-hello-world></wc-md-hello-world>
*/

pages.push({ mdFile, label, route, template, filePath, fileName, relativeExpectedPath });
Expand All @@ -97,6 +101,19 @@ const createGraphFromPages = async (pagesDir) => {
});
};

const generateRandomElementLabel = (size) => {

const letters = 'abcedfghijklmnopqrstuvwxyz';
let short = [], rand = 0;

for (let n = 0; n < size; n = n + 1) {
rand = Math.floor(Math.random() * 25);
short.push(letters.substr(rand, 1));
}

return short.join('');
};

module.exports = generateGraph = async (compilation) => {

return new Promise(async (resolve, reject) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/tasks/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ module.exports = runProductionBuild = async(compilation) => {
};

// eslint-disable-next-line no-unused-vars
const runWebpack = async ({ context }) => {
const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.prod.js'))(context);
const runWebpack = async (compilation) => {
const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.prod.js'))(compilation);

return new Promise(async (resolve, reject) => {

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/tasks/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ const path = require('path');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');

module.exports = runDevServer = async ({ context }) => {
module.exports = runDevServer = async (compilation) => {
return new Promise(async (resolve, reject) => {

try {
const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.develop.js'))(context);
const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.develop.js'))(compilation);
const devServerConfig = webpackConfig.devServer;

let compiler = webpack(webpackConfig);
Expand Down
2 changes: 0 additions & 2 deletions packages/cli/templates/hello.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
---
path: '/hello'
label: 'hello'
template: 'page'
---

### Hello World

This is an example page built by Greenwood. Make your own in _src/pages_!
2 changes: 0 additions & 2 deletions packages/cli/templates/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
---
path: '/'
label: 'index'
template: 'page'
---

### Greenwood

This is the home page built by Greenwood. Make your own pages in src/pages/index.js!
48 changes: 38 additions & 10 deletions test/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ describe('building greenwood with a user workspace w/custom nested pages directo
await setup.run(['./packages/cli/index.js', 'build']);

blogPageHtmlPath = path.join(CONTEXT.publicDir, 'blog', '20190326', 'index.html');
customFMPageHtmlPath = path.join(CONTEXT.publicDir, 'customfm', 'index.html');
});

it('should output one JS bundle', async() => {
Expand All @@ -126,18 +127,50 @@ describe('building greenwood with a user workspace w/custom nested pages directo
});

it('should have the expected heading text within the blog page in the blog directory', async() => {
const heading = dom.window.document.querySelector('h3.wc-md-blog').textContent;
const heading = dom.window.document.querySelector('h3').textContent;

expect(heading).to.equal(defaultHeading);
});

it('should have the expected paragraph text within the blog page in the blog directory', async() => {
let paragraph = dom.window.document.querySelector('p.wc-md-blog').textContent;
let paragraph = dom.window.document.querySelector('p').textContent;

expect(paragraph).to.equal(defaultBody);
});
});

describe('a custom front-matter override page directory', () => {
const defaultPageHeading = 'Custom FM Page';
const defaultPageBody = 'This is a custom fm page built by Greenwood.';
let dom;

beforeEach(async() => {
dom = await JSDOM.fromFile(customFMPageHtmlPath);
});

it('should contain a customfm folder with an index html file', () => {
expect(fs.existsSync(customFMPageHtmlPath)).to.be.true;
});

it('should have the expected heading text within the customfm page in the customfm directory', async() => {
const heading = dom.window.document.querySelector('h3').textContent;

expect(heading).to.equal(defaultPageHeading);
});

it('should have the expected paragraph text within the customfm page in the customfm directory', async() => {
let paragraph = dom.window.document.querySelector('p').textContent;

expect(paragraph).to.equal(defaultPageBody);
});

it('should have the expected blog-template\'s blog-content class', async() => {
let layout = dom.window.document.querySelector('.blog-content');

expect(layout).to.not.equal(null);
});
});

after(async() => {
await fs.remove(CONTEXT.userSrc);
await fs.remove(CONTEXT.publicDir);
Expand All @@ -146,15 +179,10 @@ describe('building greenwood with a user workspace w/custom nested pages directo

});

// // TODO - https://github.com/ProjectEvergreen/greenwood/issues/32
// // describe('building greenwood with a user workspace w/custom app-template override', () => {

// // });

// // TODO - https://github.com/ProjectEvergreen/greenwood/issues/30
// // describe('building greenwood with a user workspace w/custom page-template override', () => {
// TODO - https://github.com/ProjectEvergreen/greenwood/issues/32
// describe('building greenwood with a user workspace w/custom app-template override', () => {

// // });
// });

describe('building greenwood with error handling for app and page templates', () => {
before(async () => {
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/mock-app/src/pages/blog/20190326/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
---
label: 'blog'
template: 'page'
imports:
header: '../../../components/header/header.js'
CSS: '../../../styles/theme.css'
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/mock-app/src/pages/customfm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
label: 'customfm'
template: 'blog'
---

### Custom FM Page

This is a custom fm page built by Greenwood.
2 changes: 0 additions & 2 deletions test/fixtures/mock-app/src/pages/hello.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
---
label: 'hello'
template: 'page'
imports:
CSS: '../styles/theme.css'
---
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/mock-app/src/pages/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
---
label: 'index'
template: 'page'
imports:
CSS: '../styles/theme.css'
---
Expand Down
Loading

0 comments on commit f96db0d

Please sign in to comment.