Skip to content
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

Enabling default app/page templates for user workspace #52

Merged
merged 5 commits into from
Apr 28, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
74 changes: 31 additions & 43 deletions packages/cli/lib/init.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,44 @@
const fs = require('fs');
const path = require('path');
const greenwoodWorkspace = path.join(__dirname, '..');
const defaultTemplateDir = path.join(greenwoodWorkspace, 'templates/');
const defaultSrc = path.join(process.cwd(), 'src');

const userWorkspace = fs.existsSync(defaultSrc)
? defaultSrc
: defaultTemplateDir;

const pagesDir = fs.existsSync(path.join(userWorkspace, 'pages'))
? path.join(userWorkspace, 'pages/')
: defaultTemplateDir;

const templatesDir = fs.existsSync(path.join(userWorkspace, 'templates'))
? path.join(userWorkspace, 'templates/')
: defaultTemplateDir;
const defaultTemplatesDir = path.join(__dirname, '../templates/');
const scratchDir = path.join(process.cwd(), './.greenwood/');
const publicDir = path.join(process.cwd(), './public');

module.exports = initContexts = async() => {

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

try {

const context = {
userWorkspace,
pagesDir,
scratchDir: path.join(process.cwd(), './.greenwood/'),
templatesDir,
publicDir: path.join(process.cwd(), './public'),
pageTemplate: 'page-template.js',
appTemplate: 'app-template.js'
// TODO: replace user workspace src path based on config see issue #40
// https://github.com/ProjectEvergreen/greenwood/issues/40
const userWorkspace = path.join(process.cwd(), 'src');
const userPagesDir = path.join(userWorkspace, 'pages/');
const userTemplatesDir = path.join(userWorkspace, 'templates/');
const userAppTemplate = path.join(userTemplatesDir, 'app-template.js');
const userPageTemplate = path.join(userTemplatesDir, 'page-template.js');

const userHasWorkspace = fs.existsSync(userWorkspace);
const userHasWorkspacePages = fs.existsSync(userPagesDir);
const userHasWorkspaceTemplates = fs.existsSync(userTemplatesDir);
const userHasWorkspacePageTemplate = fs.existsSync(userPageTemplate);
const userHasWorkspaceAppTemplate = fs.existsSync(userAppTemplate);

let context = {
scratchDir,
publicDir,
pagesDir: userHasWorkspacePages ? userPagesDir : defaultTemplatesDir,
templatesDir: userHasWorkspaceTemplates ? userTemplatesDir : defaultTemplatesDir,
userWorkspace: userHasWorkspace ? userWorkspace : defaultTemplatesDir,
pageTemplatePath: userHasWorkspacePageTemplate
? userPageTemplate
: path.join(defaultTemplatesDir, 'page-template.js'),
appTemplatePath: userHasWorkspaceAppTemplate
? userAppTemplate
: path.join(defaultTemplatesDir, 'app-template.js')
};

// TODO allow per template overrides
if (fs.existsSync(context.templatesDir)) {

// https://github.com/ProjectEvergreen/greenwood/issues/30
if (!fs.existsSync(path.join(context.templatesDir, context.pageTemplate))) {
reject('It looks like you don\'t have a page template defined. \n' +
'Please include a page-template.js in your templates directory. \n' +
'See https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/templates/page-template.js');
}

// https://github.com/ProjectEvergreen/greenwood/issues/32
if (!fs.existsSync(path.join(context.templatesDir, context.appTemplate))) {
reject('It looks like you don\'t have an app template defined. \n' +
'Please include an app-template.js in your templates directory. \n' +
'See https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/templates/app-template.js');
}
}
if (!fs.existsSync(context.scratchDir)) {
fs.mkdirSync(context.scratchDir);
if (!fs.existsSync(scratchDir)) {
fs.mkdirSync(scratchDir);
}
resolve(context);
} catch (err) {
Expand Down
15 changes: 10 additions & 5 deletions packages/cli/lib/scaffold.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ const fs = require('fs');
const path = require('path');

const writePageComponentsFromTemplate = async (compilation) => {
const createPageComponent = async (file) => {
const createPageComponent = async (file, context) => {
return new Promise(async (resolve, reject) => {
try {
let data = await fs.readFileSync(path.join(compilation.context.templatesDir, `${file.template}-template.js`));
let result = data.toString().replace(/entry/g, `wc-md-${file.label}`);
const pageTemplatePath = file.template === 'page'
? context.pageTemplatePath
: path.join(context.templatesDir, `${file.template}-template.js`);

const templateData = await fs.readFileSync(pageTemplatePath);

let result = templateData.toString().replace(/entry/g, `wc-md-${file.label}`);

result = result.replace(/page-template/g, `eve-${file.label}`);
result = result.replace(/MDIMPORT;/, `import '${file.mdFile}';`);
Expand All @@ -23,7 +28,7 @@ const writePageComponentsFromTemplate = async (compilation) => {

return new Promise(async(resolve, reject) => {
try {
let result = await createPageComponent(file);
let result = await createPageComponent(file, context);

let relPageDir = file.filePath.substring(context.pagesDir.length, file.filePath.length);
const pathLastBackslash = relPageDir.lastIndexOf('/');
Expand Down Expand Up @@ -66,7 +71,7 @@ const writeListImportFile = async (compilation) => {
const writeRoutes = async(compilation) => {
return new Promise(async (resolve, reject) => {
try {
let data = await fs.readFileSync(path.join(compilation.context.templatesDir, `${compilation.context.appTemplate}`));
let data = await fs.readFileSync(compilation.context.appTemplatePath);

const routes = compilation.graph.map(file => {
if (file.route !== '/') {
Expand Down
131 changes: 73 additions & 58 deletions test/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ const glob = require('glob-promise');
const TestSetup = require('./setup');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
let CONTEXT;

describe('building greenwood with default context (no user workspace)', () => {

before(async () => {
const testUserWorkspace = async (withoutTemplate, template) => {
before(async() => {
setup = new TestSetup();
CONTEXT = await setup.init();

// copy test app
await fs.copy(CONTEXT.testApp, CONTEXT.userSrc);
await setup.run(['./packages/cli/index.js', 'build']);
if (withoutTemplate) {
await fs.removeSync(path.join(CONTEXT.userSrc, 'templates', `${template}-template.js`));
}

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

it('should create a public directory', () => {
Expand All @@ -23,18 +29,18 @@ describe('building greenwood with default context (no user workspace)', () => {
it('should output a single index.html file (home page)', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, './index.html'))).to.be.true;
});
it('should output one JS bundle file', async () => {
expect(await glob.promise(path.join(CONTEXT.publicDir, './index.*.bundle.js'))).to.have.lengthOf(1);

it('should output one JS bundle', async() => {
expect(await glob.promise(path.join(CONTEXT.publicDir, './**/index.*.bundle.js'))).to.have.lengthOf(1);
});

it('should create a default hello page directory', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, './hello'))).to.be.true;
});

describe('default generated hello page directory', () => {
const defaultHeading = 'Hello World';
const defaultBody = 'This is an example page built by Greenwood. Make your own in src/pages!';
const defaultHeading = 'Test App';
const defaultBody = 'This is a test app using a custom user template!';
let dom;

beforeEach(async() => {
Expand All @@ -58,29 +64,6 @@ describe('building greenwood with default context (no user workspace)', () => {
});
});
});

after(async() => {
await fs.remove(CONTEXT.publicDir);
await fs.remove(CONTEXT.scratchDir);
});

});

describe('building greenwood with a user workspace w/custom nested pages directories', () => {

before(async() => {
setup = new TestSetup();
CONTEXT = await setup.init();
// copy test app
await fs.copy(CONTEXT.testApp, CONTEXT.userSrc);
await setup.run(['./packages/cli/index.js', 'build']);

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

it('should output one JS bundle', async() => {
expect(await glob.promise(path.join(CONTEXT.publicDir, './**/index.*.bundle.js'))).to.have.lengthOf(1);
});

it('should contain a nested blog page directory', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, 'blog', '20190326'))).to.be.true;
Expand Down Expand Up @@ -111,53 +94,85 @@ describe('building greenwood with a user workspace w/custom nested pages directo
expect(paragraph).to.equal(defaultBody);
});
});

after(async() => {
await fs.remove(CONTEXT.userSrc);
await fs.remove(CONTEXT.publicDir);
await fs.remove(CONTEXT.scratchDir);
});

});

// // 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', () => {

// // });
describe('building greenwood with default context (no user workspace)', () => {

describe('building greenwood with error handling for app and page templates', () => {
before(async () => {
setup = new TestSetup();
CONTEXT = await setup.init();

// create empty template directory
await fs.mkdirSync(CONTEXT.userSrc);
await fs.mkdirSync(CONTEXT.userTemplates);
await setup.run(['./packages/cli/index.js', 'build']);
});

it('should display an error if page-template.js is missing', async() => {
await setup.run(['./packages/cli/index.js'], '').catch((err) => {
expect(err).to.contain("It looks like you don't have a page template defined. ");
});
it('should create a public directory', () => {
expect(fs.existsSync(CONTEXT.publicDir)).to.be.true;
});

it('should display an error if app-template.js is missing', async () => {
// add blank page-template
await fs.writeFileSync(path.join(CONTEXT.userTemplates, 'page-template.js'), '');
await setup.run(['./packages/cli/index.js'], '').catch((err) => {
expect(err).to.contain("It looks like you don't have an app template defined. ");
describe('public directory output', () => {
it('should output a single index.html file (home page)', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, './index.html'))).to.be.true;
});

it('should output one JS bundle file', async () => {
expect(await glob.promise(path.join(CONTEXT.publicDir, './index.*.bundle.js'))).to.have.lengthOf(1);
});

it('should create a default hello page directory', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, './hello'))).to.be.true;
});

describe('default generated hello page directory', () => {
const defaultHeading = 'Hello World';
const defaultBody = 'This is an example page built by Greenwood. Make your own in src/pages!';
let dom;

beforeEach(async() => {
dom = await JSDOM.fromFile(path.resolve(CONTEXT.publicDir, 'hello/index.html'));
});

it('should output an index.html file within the default hello page directory', () => {
expect(fs.existsSync(path.join(CONTEXT.publicDir, './hello', './index.html'))).to.be.true;
});

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

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

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

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

after(async() => {
await fs.remove(CONTEXT.userSrc);
await fs.remove(CONTEXT.publicDir);
await fs.remove(CONTEXT.scratchDir);
});

});

describe('building greenwood with a user workspace w/custom nested pages directories', () => {
testUserWorkspace();
});

describe('building greenwood with user workspace that doesn\'t contain app template', () => {
const withoutTemplate = true;

testUserWorkspace(withoutTemplate, 'app');
});
describe('building greenwood with user workspace that doesn\'t contain page template', () => {
const withoutTemplate = true;

testUserWorkspace(withoutTemplate, 'page');
});