diff --git a/TODO.md b/TODO.md index ed7184f..8ee6098 100644 --- a/TODO.md +++ b/TODO.md @@ -21,7 +21,7 @@ - [x] Rename all hooks to dot-first notation; rewrite `lookupFlecks()`. - [x] ensureUniqueReduction moved into invokeMerge - [x] `bootstrap({without: ['badplatform']})` should be handled by passing `{platforms: ['!badplatform']}` -- [ ] static documentation site generator +- [x] documentation site generator - [ ] config validation - [ ] hints for hook types - [ ] user redux server hydrate fails if no user in req @@ -31,7 +31,7 @@ - [ ] @babel/register@7.18.x has a bug - [ ] `$flecks/db/sequelize` should be `$flecks/db.sequelize` - [x] `url()` in styles breaks HMR -- [ ] 2 underscores for `FLECKS_ENV` variables +- [x] 2 underscores for `FLECKS_ENV` variables - [x] flecks add # Next diff --git a/packages/create-app/src/cli.js b/packages/create-app/src/cli.js index be3323b..dd7e452 100644 --- a/packages/create-app/src/cli.js +++ b/packages/create-app/src/cli.js @@ -39,9 +39,7 @@ const { throw new Error(`@flecks/create-app: invalid app name: ${errors.join(', ')}`); } const destination = join(FLECKS_CORE_ROOT, app); - if (!app.startsWith('@')) { - app = `@${app}/monorepo`; - } + const name = app.startsWith('@') ? app : `@${app}/monorepo`; if (!await testDestination(destination)) { const error = new Error( `@flecks/create-app: destination '${destination} already exists: aborting`, @@ -49,13 +47,16 @@ const { error.code = 129; throw error; } - const fileTree = await move(app, join(__dirname, 'template'), 'app', flecks); + const fileTree = await move(name, join(__dirname, 'template'), 'app', flecks); fileTree.pipe( 'build/flecks.yml', transform((chunk, encoding, done, stream) => { const yml = loadYml(chunk); - yml['@flecks/core/server'] = {packageManager}; - stream.push(dumpYml(yml, {sortKeys: true})); + if ('npm' !== packageManager) { + yml['@flecks/core/server'] = {packageManager}; + } + yml['@flecks/core'] = {id: app}; + stream.push(dumpYml(yml, {forceQuotes: true, sortKeys: true})); done(); }), ); @@ -67,6 +68,6 @@ const { // eslint-disable-next-line no-console console.error(error); } - }); + }); await program.parseAsync(process.argv); })(); diff --git a/packages/web/package.json b/packages/web/package.json index fb0f3ab..5adb243 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -45,7 +45,7 @@ "@babel/types": "^7.17.0", "@flecks/core": "^2.0.3", "@webpack-cli/serve": "^2.0.5", - "add-asset-html-webpack-plugin": "^6.0.0", + "add-asset-html-webpack-plugin": "^3.2.2", "assert": "^2.1.0", "autoprefixer": "^9.8.6", "before-build-webpack": "^0.2.13", diff --git a/website/docs/adding-a-fleck.mdx b/website/docs/adding-a-fleck.mdx deleted file mode 100644 index 667902c..0000000 --- a/website/docs/adding-a-fleck.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Adding a fleck -description: Add a fleck to your application to extend its functionality. ---- - -# Adding a fleck - -`@flecks/web` is a fleck that builds and serves a webpage. You can add it to your application -using flecks: - -```bash -npx flecks add @flecks/web -``` - -Now, if you run `npm start`, you'll see a line in the output: - -``` - @flecks/web/server/http HTTP server up @ 0.0.0.0:32340! -``` - -## Finally... a white page? - -If you visit `localhost:32340` in your browser, you should now see... a blank white page! Don't fret -though; if you open the devtools in your browser, you will see a little messaging from your -application that will look something like: - -``` -[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled. -[HMR] Waiting for update signal from WDS... -flecks client v2.0.3 loading runtime... -``` - -This is a good sign! This means we successfully added a web server with HMR enabled by default. -Oh, the possibilities... - -## Proceed with the hooking - -How does flecks know to start the web server when the application starts? Great question! This is -accomplished through the use of hooks. You'll see how to configure that hook in the next section. - -For now, we'll learn how to create our own fleck and do a little hooking of our own. Take that, dad! diff --git a/website/docs/adding-flecks.mdx b/website/docs/adding-flecks.mdx new file mode 100644 index 0000000..7bce271 --- /dev/null +++ b/website/docs/adding-flecks.mdx @@ -0,0 +1,115 @@ +--- +title: Adding flecks +description: Add flecks to your application to extend its functionality. +--- + +# Adding flecks + +`@flecks/web` is a fleck that builds and serves a webpage. You can add it to your application +using the CLI: + +```bash +npx flecks add @flecks/web +``` + +Now, if you run `npm start`, you'll see a line in the output: + +``` + @flecks/web/server/http HTTP server up @ 0.0.0.0:32340! +``` + +## Finally... a white page? + +If you visit `localhost:32340` in your browser, you should now see... a blank white page! Don't fret +though; if you open the devtools in your browser, you will see a little messaging from your +application that will look something like: + +``` +[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled. +[HMR] Waiting for update signal from WDS... +flecks client v2.0.3 loading runtime... +``` + +This is a good sign! This means we successfully added a web server with HMR enabled by default. +Oh, the possibilities... + +## Proceed with the hooking + +Let's make our fleck `say-hello` hook into `@flecks/web` client to do something when the client +comes up (e.g. the browser loads the page). + +```javascript title="packages/say-hello/src/index.js" +export const hooks = { + // highlight-start + '@flecks/web/client.up': async () => { + window.document.body.append('hello world'); + }, + // highlight-end + '@flecks/server.up': async (flecks) => { + const {id} = flecks.get('@flecks/core'); + process.stdout.write(` hello server: ID ${id}\n`); + }, +}; +``` + +Now, restart your application and refresh your website. Glorious, isn't it? + +![An image of our simple hello world application running inside a Chromium browser window](./flecks-web.png) + +## Everything so far... plus Electron! + +Let's add another core fleck. flecks ships with a core fleck `@flecks/electron`. This runs your +application inside of an instance of [Electron](https://www.electronjs.org/). You'll add the fleck: + +```bash +npx flecks add @flecks/electron +``` + +Then you'll update your `build/flecks.yml` like so: + +```yml +'@flecks/core': + id: 'hello-world' +'@flecks/electron': {} +// highlight-start +'@flecks/server': + up: + - '...' + - '@flecks/web' + - '@flecks/electron' +// highlight-end +'@flecks/web': {} +'@hello-world/say-hello:./packages/say-hello/src': {} +``` + +### ~~flecking~~ pecking order + +We added some configuration to `@flecks/server`. The `up` key configures the order in which flecks +are initialized when the server comes up. We make sure `@flecks/web` serves a webpage before +`@flecks/electron` tries to visit it. + +:::tip + +`'...'` just means "everything else": if any other flecks implement that hook then they will run +here in an **undefined** order. It is valid to provide entries both before and after `'...'`, but +`'...'` must only appear one time per list. + +The default configuration of +`@flecks/server.up` is simply: + +```yml +'@flecks/server': + up: + - '...' +``` + +However in this case the order of hook execution is undefined. That's why we configure it +explicitly. + +::: + +Finally `npm start` and you will see something like this: + +![An image of our simple hello world application running inside an Electron window](./flecks-electron.png) + +Isn't it beautiful? :relieved: diff --git a/website/docs/configuration.mdx b/website/docs/configuration.mdx index a251d33..7bd8e7a 100644 --- a/website/docs/configuration.mdx +++ b/website/docs/configuration.mdx @@ -5,8 +5,8 @@ description: Configure `build/flecks.yml` and your application. # Configuration -You have a flecks application! ...but it doesn't do much. This is because a flecks application is -composed of individual flecks and by default, your application will have only two flecks: +You have a flecks application! ...but it doesn't do much. By default, your application will have +only two flecks: `@flecks/core` and `@flecks/server`. Your `build/flecks.yml` file will look like this: ```yml title="build/flecks.yml" @@ -20,24 +20,22 @@ For a deep dive of configurable core flecks, see ## `build/flecks.yml` -A good first configuration step is to set the ID of your application. +Your flecks application stores its build configuration in a directory located at `build`. By +default, there is a single file located there: `flecks.yml`. This is where all the individual +flecks are configured. -Your application's ID is configured at the `id` key of `@flecks/core`'s configuration. To set your -application's ID to `hello_world`, update your `build/flecks.yml` to look like this: +Your application's ID is configured at the `id` key of `@flecks/core`'s configuration: ```yml title="build/flecks.yml" // highlight-start '@flecks/core': - id: 'hello_world' + id: 'hello-world' // highlight-end '@flecks/server': {} ``` -## Adding more +Notice that the ID was set automatically by the app creation utility. -If you were studious enough to take a peek at [the generated configuration page](/docs/flecks/@flecks/dox/config) -above, you may have noticed that there were a lot more flecks there than just the two in our -application. +## Moving forward -For instance, there is a `@flecks/web` fleck that turns your little old server application into one -that can build and serve a webpage. We'll see how to add it in the next section. +In the next section, we'll look at how to create a fleck. diff --git a/website/docs/creating-a-fleck.mdx b/website/docs/creating-a-fleck.mdx index 93248c8..774faca 100644 --- a/website/docs/creating-a-fleck.mdx +++ b/website/docs/creating-a-fleck.mdx @@ -4,30 +4,27 @@ description: A fleck is a module but also so much more. --- If you are following along from the previous getting started -[configuration page](./configuration), you have an application with 3 flecks: +[configuration page](./configuration), you have an application with 2 flecks: - `@flecks/core` - `@flecks/server` -- `@flecks/web`
- About that "3 flecks" thing... + About that "2 flecks" thing... - Actually, your server application has 6 flecks at this point: + Actually, your server application has **4 flecks** at this point: - `@flecks/core` - `@flecks/core/server` - `@flecks/server` - `@flecks/server/server` - - `@flecks/web` - - `@flecks/web/server` flecks will load the `[...]/server` fleck under any fleck that is loaded on the server. This is also the case when using `@flecks/web` which will automatically load `[...]/client` flecks which are only loaded in the browser. We'll be exploring this specifically in the next section. If you're intersted in diving deeper, see [the platforms concept page](#todo). - Some frameworks make it a little cheesier to work with isomorphic code, but the flecks + Some frameworks make it a little more opaque to work with isomorphic code, but the flecks philosophy is that visibility is believability: you'll have to be explicit about which code runs where.
@@ -63,7 +60,6 @@ After some output, you'll find your new fleck at `packages/say-hello`. Let's ins '@flecks/core': id: 'hello_world' '@flecks/server': {} -'@flecks/web': {} // highlight-next-line '@hello-world/say-hello:./packages/say-hello/src': {} ``` @@ -107,68 +103,53 @@ There is a source file at `packages/say-hello/src/index.js` but for now it's emp out a bit: ```javascript title="packages/say-hello/src/index.js" -exports.hooks = { - '@flecks/web/client.up': async () => { - window.document.body.append('hello world'); +export const hooks = { + '@flecks/server.up': async () => { + process.stdout.write(' hello server\n'); }, }; ``` -Now, restart your application and visit your website. Glorious, isn't it? - -## Everything so far... plus Electron! - -Let's add another core fleck. flecks ships with a core fleck `@flecks/electron`. This runs your -application inside of an instance of [Electron](https://www.electronjs.org/). You'll add the fleck: +Now, restart your application: ```bash -npx flecks add @flecks/electron +npm run start ``` -Then you'll update your `build/flecks.yml` like so: +You will be greeted by a line in the output: -```yml -'@flecks/core': - id: 'hello_world' -'@flecks/electron': {} -// highlight-start -'@flecks/server': - up: - - '...' - - '@flecks/web' - - '@flecks/electron' -// highlight-end -'@flecks/web': {} -'@hello-world/say-hello:./packages/say-hello/src': {} +```terminal + hello server ``` -### ~~flecking~~ pecking order +### flecks injection -We added some configuration to `@flecks/server`. The `up` key configures the order in which flecks -are initialized when the server comes up. We make sure `@flecks/web` serves a webpage before -`@flecks/electron` tries to visit it. +Hook implementations may receive arguments. After any arguments, the `flecks` instance is always +passed. -:::tip +`@flecks/server.up` doesn't pass any arguments, so the `flecks` instance is the first argument. +Let's see how to use the instance to read some configuration: -`'...'` just means "everything else": if any other flecks implement that hook then they will run -here. It is valid to provide entries both before and after `'...'`. - -The default configuration of -`@flecks/server.up` is simply: - -```yml -'@flecks/server': - up: - - '...' +```javascript title="packages/say-hello/src/index.js" +export const hooks = { + '@flecks/server.up': async (flecks) => { + const {id} = flecks.get('@flecks/core'); + process.stdout.write(` hello server: ID ${id}\n`); + }, +}; ``` -However in this case the order of hook execution is undefined. That's why we configure it -explicitly. +This time, you will see: + +```terminal + hello server: ID hello-world +``` + +:::note + +...or whatever your application's ID is. We're assuming you're following along from +[the configuration page](./configuration). ::: -Finally `npm start` and you will see something like this: - -![An image of our simple hello world application running inside an Electron window](./flecks-electron.png) - -Isn't it beautiful? :relieved: +Next, we'll add and interact with some of the flecks shipped by default. diff --git a/website/docs/environment.mdx b/website/docs/environment.mdx index af29e0a..53b75bb 100644 --- a/website/docs/environment.mdx +++ b/website/docs/environment.mdx @@ -18,37 +18,35 @@ so: ``` When running your application in different execution environments (say, production) you may want to -override configuration such as this. This is done by using the a prefix followed by the -fleck name and the key. The template literal for such a transformation would look like: +override configuration such as this. This is done by like so: ### Syntax ```javascript -`FLECKS_ENV__${Flecks.environmentalize(path)}__${key}` +`FLECKS_ENV__${Flecks.environmentalize(fleck)}__${key}` ``` -:::note +:::tip -Notice the `environmentalize` transformation: `@flecks/core`'s `id` key is set using the -following variable: +As an example, `@flecks/core`'s `id` key is set using the following variable: ```bash FLECKS_ENV__flecks_core__id=foobar ```
- `Flecks.environmentalize` + `Flecks.environmentalize` implementation ```javascript static environmentalize(path) { return path - // - `@flecks/core` -> `FLECKS_CORE` + // - `@flecks/core` -> `flecks_core` .replace(/[^a-zA-Z0-9]/g, '_') .replace(/_*(.*)_*/, '$1'); } ```
-Also note that the fleck path and key are still case-sensitive. This is because they are +Note that the fleck path and key are still case-sensitive. This is because they are user-defined. ::: diff --git a/website/docs/flecks-web.png b/website/docs/flecks-web.png new file mode 100644 index 0000000..e5da34c Binary files /dev/null and b/website/docs/flecks-web.png differ diff --git a/website/sidebars.js b/website/sidebars.js index 08d6e61..e0b3434 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -11,8 +11,8 @@ export default { items: [ 'installation', 'configuration', - 'adding-a-fleck', 'creating-a-fleck', + 'adding-flecks', ], }, {