Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ProjectEvergreen/greenwood into t…
Browse files Browse the repository at this point in the history
…ask/fix-issue-32-page-app-templates
  • Loading branch information
hutchgrant committed Apr 28, 2019
2 parents b066cac + c90c662 commit 2d9279b
Show file tree
Hide file tree
Showing 28 changed files with 242 additions and 270 deletions.
90 changes: 62 additions & 28 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 All @@ -117,7 +152,6 @@ By default, Greenwood will supply its own [app-template](https://github.com/Proj
An `app-template.js` must follow the [default template](https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/templates/app-template.js#L1-L13) in that it must include the lit-redux-router, redux, redux-thunk, lazy-reducer-enhancer and it must create a redux store. You may import any additional components or tools you wish but the `import './list';` [must be included](https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/templates/app-template.js#L16) in order to import all your generated static page components. Do not change the path and you can ignore the fact that this file doesn't exist, it will be created on build in memory. In the [render function](https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/templates/app-template.js#L21-L26), it must include somewhere:

```html
<lit-route path="/" component="home-page"></lit-route>
MYROUTES
```

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
12 changes: 6 additions & 6 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 Expand Up @@ -100,7 +100,7 @@ module.exports = (context) => {
),

new HtmlWebpackPlugin({
template: path.join(context.scratchDir, 'index.html'),
template: path.join(context.scratchDir, context.indexPageTemplate),
chunksSortMode: 'dependency'
})
]
Expand Down
37 changes: 25 additions & 12 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 All @@ -48,12 +48,12 @@ module.exports = (context) => {
plugins: [
// new webpack.HotModuleReplacementPlugin(),
new FilewatcherPlugin({
watchFileRegex: [`/${context.userWorkspace}/`],
watchFileRegex: [`/${context.userWorkspace}/`],
onReadyCallback: () => {
console.log(`Now serving Development Server available at http://${host}:${port}`);
},
// eslint-disable-next-line no-unused-vars
onChangeCallback: async () => {
onChangeCallback: async (path) => {
rebuild();
},
usePolling: true,
Expand All @@ -64,17 +64,30 @@ module.exports = (context) => {
fileName: 'manifest.json',
publicPath
}),
// TODO magic string paths (index.html)
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(context.scratchDir, 'index.dev.html'),
publicPath
template: path.join(context.scratchDir, context.indexPageTemplate),
spaIndexFallbackScript: `
<script>
(function(){
var redirect = sessionStorage.redirect;
delete sessionStorage.redirect;
if (redirect && redirect != location.href) {
history.replaceState(null, null, redirect);
}
})();
</script>
`
}),
// TODO magic string paths (404.html)
new HtmlWebpackPlugin({
filename: '404.html',
template: path.join(context.scratchDir, '404.dev.html'),
publicPath
filename: context.notFoundPageTemplate,
template: path.join(context.scratchDir, context.notFoundPageTemplate),
spaIndexFallbackScript: `
<script>
sessionStorage.redirect = location.href;
</script>
<meta http-equiv="refresh" content="0;URL='${publicPath}'"></meta>
`
})
]
});
Expand Down
10 changes: 5 additions & 5 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 All @@ -16,9 +16,9 @@ module.exports = (context) => {

plugins: [
new HtmlWebpackPlugin({
filename: '404.html',
template: path.join(context.scratchDir, '404.html'),
publicPath: configWithContext.output.publicPath
filename: context.notFoundPageTemplate,
template: path.join(context.scratchDir, context.notFoundPageTemplate),
publicPath: configWithContext.publicPath
})
]

Expand Down
25 changes: 21 additions & 4 deletions packages/cli/lib/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const createGraphFromPages = async (pagesDir) => {
template = template || 'page';

// get remaining string after user's pages directory
let subDir = filePath.substring(pagesDir.length, filePath.length);
let subDir = filePath.substring(pagesDir.length - 1, filePath.length);

// get index of seperator between remaining subdirectory and the file's name
const seperatorIndex = subDir.lastIndexOf('/');
Expand All @@ -47,21 +47,24 @@ 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`;
relativeExpectedPath = `'../${completeNestedPath}/${fileName}/${fileName}.js'`;
} else {
mdFile = `./${fileRoute}.md`;
mdFile = `.${fileRoute}.md`;
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
30 changes: 10 additions & 20 deletions packages/cli/lib/scaffold.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ const writeRoutes = async(compilation) => {
let data = await fs.readFileSync(compilation.context.appTemplatePath);

const routes = compilation.graph.map(file => {
if (file.route !== '/') {
return `<lit-route path="${file.route}" component="eve-${file.label}"></lit-route>\n\t\t\t\t`;
}
return `<lit-route path="${file.route}" component="eve-${file.label}"></lit-route>\n\t\t\t\t`;
});

const result = data.toString().replace(/MYROUTES/g, routes.join(''));
Expand All @@ -91,25 +89,17 @@ const writeRoutes = async(compilation) => {
};

// eslint-disable-next-line no-unused-vars
const setupIndex = async(compilation) => {
const setupIndex = async({ context }) => {
return new Promise(async (resolve, reject) => {
const context = compilation.context;
let indexHtml = 'index.html';
let notFoundHtml = '404.html';
let devIndexHtml = 'index.dev.html';
let devNotFoundHtml = '404.dev.html';

try {

// create redirect 404 pages for lit-redux-router + SPA fallback for development
if (process.env.NODE_ENV === 'development') {
fs.copyFileSync(path.resolve(context.templatesDir, devNotFoundHtml), path.join(context.scratchDir, devNotFoundHtml));
fs.copyFileSync(path.resolve(context.templatesDir, devIndexHtml), path.join(context.scratchDir, devIndexHtml));
}

fs.copyFileSync(path.resolve(context.templatesDir, notFoundHtml), path.join(context.scratchDir, notFoundHtml));
fs.copyFileSync(path.resolve(context.templatesDir, indexHtml), path.join(context.scratchDir, indexHtml));

fs.copyFileSync(
path.join(context.templatesDir, context.indexPageTemplate),
path.join(context.scratchDir, context.indexPageTemplate)
);
fs.copyFileSync(
path.join(context.templatesDir, context.notFoundPageTemplate),
path.join(context.scratchDir, context.notFoundPageTemplate)
);
resolve();
} catch (err) {
reject(err);
Expand Down
8 changes: 3 additions & 5 deletions packages/cli/lib/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ const PORT = '8000';
const runBrowser = async (compilation) => {

try {
return await Promise.all(compilation.graph.map(file => {
const route = file.route === '/' ? '' : file.route;

return browserRunner(`http://127.0.0.1:${PORT}/${route}`, file.label, file.route, compilation.context.publicDir);
return await Promise.all(compilation.graph.map(({ route, label }) => {
return browserRunner(`http://127.0.0.1:${PORT}${route}`, label, route, compilation.context.publicDir);
}));
} catch (err) {
// eslint-disable-next-line no-console
Expand All @@ -26,7 +24,7 @@ module.exports = serializeBuild = async (compilation) => {
port: PORT,
https: false,
directory: compilation.context.publicDir,
spa: 'index.html'
spa: compilation.context.indexPageTemplate
});

await runBrowser(compilation);
Expand Down
Loading

0 comments on commit 2d9279b

Please sign in to comment.