-
Notifications
You must be signed in to change notification settings - Fork 10
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
RFC: User Config file integration #53
Conversation
Signed-off-by: HutchGrant <h.g.utchinson@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💥
Nice job! A little beyond the scope, but the changes seem to work well together and you documented them nicely with unit tests, so I think it's OK to set this a base level for this feature. and it's important to reward ambition too, can't always be super sticklers I suppose. 😄 🏆
Just left a couple minor feedback points for review. And for going forward, we'll want to try and track each new config feature we want to add as a new issue.
@@ -1,29 +1,30 @@ | |||
require('colors'); | |||
const initConfig = require('./config'); | |||
const initContext = require('./init'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably not for this issue, but maybe we should create an issue to change init.js to context.js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
#57
test/fixtures/greenwood.config.json
Outdated
@@ -0,0 +1,9 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we set the indentation to 2 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea I don't know why my editor defaults to 4, have to get around to changing that.
test/setup.js
Outdated
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src') | ||
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src'), | ||
userCfgPath: path.join(__dirname, 'fixtures', 'greenwood.config.json'), | ||
userCfgRootPath: path.join(__dirname, '..', 'greenwood.config.json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how come we are using this second config file? The names are really close and hard to distinguish. Maybe we just need more fixtures?
My comment here about creating "cases" of tests might be an appropriate justification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
second config is just the hardcoded path to where the config will be copied. Hence: userCfgRootPath
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, so basically for mocking the user's project root, where their own greenwood.config.json would be located?
@@ -160,4 +160,67 @@ describe('building greenwood with error handling for app and page templates', () | |||
await fs.remove(CONTEXT.scratchDir); | |||
}); | |||
|
|||
}); | |||
|
|||
describe('building greenwood with user provided config file', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the intent is to also test with a nested directory output, lets add it to the describe
description, otherwise I think we can drop those additional tests for nested pages since they are already covered above, and if our architecture is sound, anything that breaks nested directories here should in theory also break it up there, which is a better logical block to solve it in.
In essence, we can try and have tests that take advantage of other tests already testing for specific outputs, so tests can have minimal overlap while still breaking each other if something goes wrong when making a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They aren't covered under this scenario, thats why they are there. In theory they should break earlier in the tests, but not necessarily with all the tests.
Every single situation the public directory, js bundle, hello, nested, need to be tested.
When the source directory changes(which it does as per this test when a config file is copied), everything has to be retested or at least partially.
For example, had we tested the index route in the nested pages describe here(using user workspace mock-app), we would have caught the error for #54 which I just found today because one of the duplicate files which was in the correct path wasn't serialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the source directory changes(which it does as per this test when a config file is copied), everything has to be retested or at least partially.
Right good point.
And I think that's a good approach to take here, as for changing something like the userWorkspace
, essentially we would want to run everything from the beginning.
One thing that isn't so clear here though, and maybe this could just be made more clear in a describe
or it
is the specific configuration used and making sure to assert
on those specific values somehow?
I would expect to see specific tests to cover each config API being supported (userWorkspace
, devServer
), even if it means recreating a new config file or amending dynamically in some way to make it as explicit as possible, since we should make sure that if the user provides supported configuration items
- sourceDirectory
- devServer
- etc
That we call those out specifically in our testing somehow, like though
- return value of
initConfig
- output of file paths after running
build
- webpack config?
Although some cases may have some overlap, I think it's OK if it means that we can define and test the critical paths and outputs of a given feature / workflow / etc for the project if it ensures our tests can be as faithful to how a user would also setup / run our code. Providing a great and accurate development / testing environment we'll provide us much more grounded and confident in the usefulness and coverage of our tests.
A little duplication for the sake of clarity and setup is a positive tradeoff / investment in my book 👍
I always like to think to myself, the convenience in making build tools is to the user, not the maintainer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So sorry, for just catching this
Are we using json or js? In the code it's the former, in the README it's the latter.
I think I would prefer .js since if we want to add more build time features (like webpack plugins, or anything dynamic really) it would only be possible in a JS file.
Plus, a JS file can be linted. 👌
test/setup.js
Outdated
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src') | ||
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src'), | ||
userCfgPath: path.join(__dirname, 'fixtures', 'greenwood.config.json'), | ||
userCfgRootPath: path.join(__dirname, '..', 'greenwood.config.json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, so basically for mocking the user's project root, where their own greenwood.config.json would be located?
right, you need to
|
but is that really the simplest config file for the user? module.exports = {
source: 'src2',
publicPath: '/',
devServer: {
port: 1984,
host: 'localhost'
},
meta: {}
}; instead of
|
test/setup.js
Outdated
const context = { | ||
...ctx, | ||
userSrc: path.join(__dirname, '..', 'src'), // static src | ||
userTemplates: path.join(__dirname, '..', 'src', 'templates'), // static src/templates for testing empty templates dir, redundant in #38 | ||
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src') | ||
testApp: path.join(__dirname, 'fixtures', 'mock-app', 'src'), | ||
userCfgPath: path.join(__dirname, 'fixtures', 'greenwood.config.js'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would the mock config make sense being located in the mock-app
folder?
Then testApp
could be used to get to the paths for the config too. I think in general we will probably want to revisit this for #56 since I want to make sure we are very precise with the setup / teardown of our tests. In case based development, we'll probably favor composition over inheritance.
Maybe each test case can provide it's own custom context
to TestSetup
to make sure this setup function doesn't grow too large, handle too many cases, and add too much coupling to our tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know to me that seems like more code than simply adding variables where needed but I can see how that could be beneficial. Do you have an idea how to go about that?
config could be within mock-app sure, but then to use test-app we'd have to modify it from src
and either:
- a) hardcode a path within the test itself for
src
andgreenwood.config.js
or - b) add an additional context variable specifically for
src
.
We could do this a hundred times and continue to adjust the tests but I'd prefer to do it after these changes have been applied. So that I can move on this week, in addition to refactoring all these tests at once, not just specific for one single PR or another PR. Why not deal with it at once? This too would be a large change as well. This would actually reduce the amount of work, as the process of merging those changes, testing, then reviewing those changes, with the other PRs would take longer than doing it at once.
The point is while I'm waiting for it to be reviewed, whatever I do to the tests, I want to be able to work on something else. Which I can't, if we hold this back because of preferred organization of test variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point is while I'm waiting for it to be reviewed, whatever I do to the tests, I want to be able to work on something else. Which I can't, if we hold this back because of preferred organization of test variables.
I didn't say / imply that though I don't think? I did say..
I think in general we will probably want to revisit this for #56
So anyway, I'm just trying to chat about the code in front of me, while it is in front of me is all. Please don't feel bad if I talk or ask a lot of questions in PRs, I'm just trying to understand the decision making process from your POV so I can best understand that and try and make equally informed decisions for when that time comes.
@@ -160,4 +160,67 @@ describe('building greenwood with error handling for app and page templates', () | |||
await fs.remove(CONTEXT.scratchDir); | |||
}); | |||
|
|||
}); | |||
|
|||
describe('building greenwood with user provided config file', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the source directory changes(which it does as per this test when a config file is copied), everything has to be retested or at least partially.
Right good point.
And I think that's a good approach to take here, as for changing something like the userWorkspace
, essentially we would want to run everything from the beginning.
One thing that isn't so clear here though, and maybe this could just be made more clear in a describe
or it
is the specific configuration used and making sure to assert
on those specific values somehow?
I would expect to see specific tests to cover each config API being supported (userWorkspace
, devServer
), even if it means recreating a new config file or amending dynamically in some way to make it as explicit as possible, since we should make sure that if the user provides supported configuration items
- sourceDirectory
- devServer
- etc
That we call those out specifically in our testing somehow, like though
- return value of
initConfig
- output of file paths after running
build
- webpack config?
Although some cases may have some overlap, I think it's OK if it means that we can define and test the critical paths and outputs of a given feature / workflow / etc for the project if it ensures our tests can be as faithful to how a user would also setup / run our code. Providing a great and accurate development / testing environment we'll provide us much more grounded and confident in the usefulness and coverage of our tests.
A little duplication for the sake of clarity and setup is a positive tradeoff / investment in my book 👍
I always like to think to myself, the convenience in making build tools is to the user, not the maintainer.
…n/greenwood into rfc/user-config-issue-40
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is pretty much there. Just a little input validation and then I think this should be good to merge. ✅
…fc/user-config-issue-40
packages/cli/lib/config.js
Outdated
@@ -23,7 +23,7 @@ module.exports = readAndMergeConfig = async() => { | |||
const userCfgFile = require(path.join(process.cwd(), 'greenwood.config.js')); | |||
|
|||
// prepend paths with current directory | |||
if (userCfgFile.source) { | |||
if (userCfgFile.source && !path.isAbsolute(userCfgFile.source)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be good to be a little more robust in our error handling here, since we're not checking that any of these directories exist first, which I think is important given how fundamental this particular option is to bootstrapping the entire tool.
Also, we can provide direct feedback to the user too. ex.
if (userCfgFile.workspace) {
const workspace = userCfgFile.workspace;
// 1) is it an absolute path that exists? let's just use it
// 2) else if it exists in process.cwd(), then use that
// 3) else, give up and error out to the user
if(path.isAbsolute(workspace) && fs.existsSync(workspace) {
config.workspace = workspace;
} else if(fs.existsSync(path.join(process.cwd(), workspace))) {
path.join(process.cwd(), workspace)
} else {
// sorry, we couldn't find your workspace :(
// common issues to check might be:
// - typo in your workspace directory name, or in greenwood.config.js
// - if using relative paths, make sure your workspace is in the same cwd as _greenwood.config.js_
// - consider using an absolute path, e.g. path.join(__dirname, 'my', 'custom', 'path') // <__dirname>/my/custom/path/
// reject()
}
}
Almost there!! 🏁 🏃 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a www folder with nothing in it, created a greenwood.config.js in the root
module.exports = {
workspace: 'www',
publicPath: '/owen',
devServer: {
port: 1981,
host: 'localhost'
}
};
Looking good!
$ yarn build
yarn run v1.12.3
$ node ./packages/cli/index.js build
-------------------------------------------------------
Welcome to Greenwood ♻️
-------------------------------------------------------
Reading project config
Initializing project workspace contexts
Generating graph of workspace files...
Scaffolding out project files...
Generate pages from templates...
Writing imports for md...
Writing Lit routes...
setup index page and html
Scaffolding complete.
Building project for production.
Building SPA from compilation...
webpack build complete
...................................
Static site generation complete!
...................................
✨ Done in 11.52s.
Owens-MBP-2:greenwood owenbuckley$ yarn devel
Owens-MBP-2:greenwood owenbuckley$ cat public/index.html
<!DOCTYPE html><html lang="en" prefix="og:http://ogp.me/ns#"><head><style>body {transition: opacity ease-in 0.2s; }
body[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; }
</style>
<title>My App</title>
<meta charset="utf-8">
<meta name="description" content="Greenwood">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="description" content="A modern and performant static site generator supporting Web Component based development.">
.
.
.
<eve-app></eve-app>
<script type="text/javascript" src="/owen/index.861cad5fddf22530b046.bundle.js"></script>
$ yarn develop
yarn run v1.12.3
$ yarn clean && node ./packages/cli/index.js develop
$ rimraf ./.greenwood && rimraf ./public
-------------------------------------------------------
Welcome to Greenwood ♻️
-------------------------------------------------------
Reading project config
Initializing project workspace contexts
Generating graph of workspace files...
Scaffolding out project files...
Generate pages from templates...
Writing imports for md...
Writing Lit routes...
setup index page and html
Scaffolding complete.
Starting local development server
.
.
.
ℹ 「wdm」: Compiled successfully.
Directory www has been added
Now serving Development Server available at http://localhost:1981
Docs look good too!
🎉
Related Issue
Resolves #40
Summary of Changes
greenwood.config.js
in root of app directory