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

Remote Templates #329

Merged
merged 54 commits into from
Sep 4, 2017
Merged

Remote Templates #329

merged 54 commits into from
Sep 4, 2017

Conversation

lukeed
Copy link
Member

@lukeed lukeed commented Aug 21, 2017

What

Allows cloning of Preact CLI compatible templates from remote repositories.

This adds a separation-of-concerns layer, relinquishing all of the what (aka, the contents) to third parties. In effect, this allows the community to share & reuse templates or recipes that the Preact CLI team is not experienced with and/or not willing to officially support.

Our community is very bright & inventive, so allowing them to create solutions to their own needs is a win for everybody! 🎉

As a result, Preact CLI will focus on two items:

  1. Scaffolding the initial project files

  2. Enhancing its commands for:
    a) optimal PWA-centric builds
    b) user-friendly development process

Why

  1. Open the doors to community-driven templates
  2. Reusable custom templates
  3. Separation of concerns
  4. Offline support

How

Use an official template:

$ preact create default my-app --yarn --git
#=> 1. Downloads 'preactjs-templates/default' locally
#=> 2. Extracts 'default/master.tar.gz' to '$CWD/my-app'
#=> 3. Installs with Yarn 
#=> 4. Inits a Git repo

Use a user template (tagged version!):

$ preact create lukeed/preact-starter#v1.1.0 my-app --name FooBar
#=> 1. Checks local cache for v1.1.0 of 'lukeed/preact-starter'
#=> 2. Downloads & Caches tag archive if not already cached
#=> 3. Extracts to '$CWD/my-app'
#=> 4. Changes 'name' within resolved 'package.json'
#=> 5. Changes 'name' within resolved 'manifest.json'
#=> 6. Installs with NPM

TODOs

  • Prompt the user when insufficient data is passed to preact create

  • Alias preact init to preact create

  • Read & Respond to "extraction hooks"
    Injecting values based on custom prompts

  • Allow optional, custom prompts on a per-template basis
    Template authors may require specific values or have a choice list for certain items


Still a WIP. I'd like to continue only once all TODO items are complete.

Closes #99, #326.

lukeed added 30 commits August 19, 2017 13:55
- declare `log-symbols` as a dependency
  - it is already a direct dependency of `ora`
- with nice symbol & formatting
- uses *sync versions, but oh well
- will need to verify a destination before extracting/downloading
- will prompt (TODO) if incomplete
- will abort if unsafe
- use more partial import statements
- uses which.sync 🙊
- update function calls
- remove `async` from `pkgScripts`
- instead of checking 5x per `setup` function
- return `async` function directly from `initialize`
- template concern
- only `default` & `full` for now
lukeed added 3 commits August 23, 2017 11:13
- PRs are still built
- somehow `recursive-copy` was picked up?
@lukeed
Copy link
Member Author

lukeed commented Aug 23, 2017

Is there any chance a Travis caching is making this error? 🤔

I've run this a few times locally (using the same Node 8.x version) and the build tests work fine.

}
} else {
// TODO: interactive
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@developit Should we really do this? This make it more complex for us to handle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's save this discussion for a future PR. I want to break it up instead of making this (even more) massive.

exports.default = [
'.gitignore',
'package.json',
'README.md',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even when we use node-glob, it sorts in the alphabetical order AFAIK. This might be an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. The above is alpha-sorted 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and it always fails in my machine 😛

lukeed added 5 commits August 26, 2017 10:09
- no need anymore!
- templates responsible own dependecies
- and style-* flags removed
- OCD strikes again
- tell user to run `npm install` first
@lukeed
Copy link
Member Author

lukeed commented Aug 26, 2017

Fixed the tests! I made the (silly) mistake of not passing the Travis flags to my local tests 🤦‍♂️ . Once I did, was clear that the failures did relate to the dependency-loader... The signature on setup.js@install changed, and it was "silently" failing (got lost in stack output).

However, in fixing it, I realized we don't even need the dependency-installer anymore!

Reason being, templates are responsible for themselves. The rest of this PR assumes that, with the tiny exception of adding package scripts if none were defined. So, in keeping the philosophy consistent, we shouldn't be installing critical build dependencies on behalf of the user.

Aside: This requires the 4 test "subjects" to install deps... we can have Travis use yarn soon.

It's no longer our job in remote-template world. 🎉

Not my job


More PRs to come, which will address all tasks & gotchas I've mentioned.

Copy link
Member

@reznord reznord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from these comments, its gold. 👍

root: 'examples/root',
simple: 'examples/simple'
full: 'preactjs-templates/default',
default: 'preactjs-templates/default',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why both full & default? Since they do the same thing.

Instead we can just add default & simple from templates.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add simple. @developit requested in Slack that we make default an alias of full

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was just thinking "principle of least surprise" here, this makes it work quite similarly to how it does in 1.0.

filter(path) {
// TODO: remove `/build/` ??
// TODO: read & respond to meta/hooks
return path.includes('/template/') && !path.includes('/build/');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't find templates/ folder, we can throw an error saying that you need a specific folder structure or sth like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Let's do that in another PR.

return error(`No \`template\` directory found within ${ repo }!`);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could even detect template/ and if it doesn't exist, assume the template is at the root. I'm fine with either, and a subsequent PR seems fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to force a template structure. When things become too flexible they become less clear and harder to debug.

dev: 'preact watch',
test: 'eslint src && preact test'
start: `if-env NODE_ENV=production && ${cmd} run -s serve || ${cmd} run -s watch`,
watch: 'preact watch'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably leave it to dev, since most users expect that 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol okay. I thought this would make more sense since the command name is watch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I waffled on this incessantly when doing the original scripts. FWIW CRA does neither, they actually use npm start for the dev server (that's why I added the env bit there).

I don't have a really compelling reason to go one way or the other here. It might be annoying for people to upgrade and find the command they know has a new name, but then it's only in the templated projects - anything created with 1.x will work just fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, however, it is a major release, so this would be the time to change it, if any.


// TODO
// const ours = ['empty', 'full', 'simple', 'root'];
const ours = ['default', 'full'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be default & simple here too! (coz we can run tests on those templates)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above ^^

exports.default = [
'.gitignore',
'package.json',
'README.md',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and it always fails in my machine 😛

Copy link
Member

@reznord reznord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 LGTM!

ping @developit for further review on this 😄

root: 'examples/root',
simple: 'examples/simple'
full: 'preactjs-templates/default',
default: 'preactjs-templates/default',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was just thinking "principle of least surprise" here, this makes it work quite similarly to how it does in 1.0.

process.exit(1);
}
let repo = TEMPLATES[argv.template] || argv.template;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be reasonable here to do something like: "if repo has no /, assume preactjs-templates/${repo}"? That way any template we add to the preactjs-templates org becomes a default option.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Or just include new official templates (should not be often!) as patch releases.

filter(path) {
// TODO: remove `/build/` ??
// TODO: read & respond to meta/hooks
return path.includes('/template/') && !path.includes('/build/');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could even detect template/ and if it doesn't exist, assume the template is at the root. I'm fine with either, and a subsequent PR seems fine.

if (pkgFile) {
pkgData = JSON.parse(await fs.readFile(pkgFile));
// Write default "scripts" if none found
pkgData.scripts = pkgData.scripts || (await addScripts(pkgData, target, isYarn));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of making scripts a wholesale override, we could merge our scripts into the template's?

pkgData.scripts = {
  ...(pkgData.scripts || {}),
  ...(await addScripts(pkgData, target, isYarn))
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could merge our scripts into the template's?

I don't think there is a necessary for that since templates will have scripts defined in the package.json file (includes our scripts too)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just sucks if the cli wants to change script down the line 😋

dev: 'preact watch',
test: 'eslint src && preact test'
start: `if-env NODE_ENV=production && ${cmd} run -s serve || ${cmd} run -s watch`,
watch: 'preact watch'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I waffled on this incessantly when doing the original scripts. FWIW CRA does neither, they actually use npm start for the dev server (that's why I added the env bit there).

I don't have a really compelling reason to go one way or the other here. It might be annoying for people to upgrade and find the command they know has a new name, but then it's only in the templated projects - anything created with 1.x will work just fine.

@@ -141,13 +134,6 @@ export default (env) => {
loader: 'sass-loader',
options: { sourceMap: true }
}
},
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What the best way for templates to add these?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preact.config.js is the only way the user can tweak the webpack config in CLI as of now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template authors have to define their own dependencies, as a rule. As of now, the template can also include a preact.config.js, but in the near future, I'll add a meta.js file (from root) that will have postinstall hooks and behaviors. Hat tip to Vue for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature] Clone from Remote Boilerplate/Template
4 participants