Repository: maizzle/framework (js)

Issue:
Using maizzle.config.js as a config file
Hello, I'm integrating maizzle into a monorepo project with many different config files in the root directory. It would be great to be able to use `maizzle.config.js` as the config name to align with other tool configs like tailwind.config.js but I can't seem to figure out how.

 I'm using the CLI to trigger the build:
```
npx maizzle build
```

Currently, in a directory with many configs:
```
/Brewfile
/config.js // <- maizzle config
/Dockerfile
/tailwind.config.js
/go.mod
/package.json
```

I hit an error when renaming the config to `maizzle.config.js` : 

```
⠋ Building emails...⠙ No template sources defined in `build.templates`, check your config.js file
/node_modules/@maizzle/framework/src/generators/output/to-disk.js:37
      throw new Error(`No template sources defined in \`build.templates\`, check your ${configFileName} file`)
```

Is there a CLI flag or environment variable I can use to set the config path? `npx maizzle build --help` doesn't have any details.

If this isn't something thats currently possible I'm happy to open a pull if you can point me in the right direction.

Thank you!

Pull request description:
feat: add support for maizzle.config.js files
### Added support for maizzle.config.js files

Fixes #1077.

This PR adds support for `maizzle.config.js` configuration file names, similar to Tailwind's `tailwind.config.js`.

Here's an overview of Maizzle commands and the config file names they'll use:

| **Command**         | **Config file name**                         |
|---------------------|----------------------------------------------|
| maizzle build       | config.js <br> maizzle.config.js             |
| maizzle build {env} | config.{env}.js <br> maizzle.config.{env}.js |
| maizzle serve {env} | config.{env}.js <br> maizzle.config.{env}.js |

Maizzle will try to look for `maizzle.config.js` first, falling back to `config.js`.

### Updated Browsersync add/remove events

We're now configuring `chokidar` to wait for files to be written to disk. This should help prevent the dev server crashing when you add files to watched paths, i.e. when pasting an image in the images folder.


Patch:
diff --git a/src/commands/serve.js b/src/commands/serve.js
index 17b136b..8161905 100644
--- a/src/commands/serve.js
+++ b/src/commands/serve.js
@@ -149,9 +149,12 @@ const serve = async (env = 'local', config = {}) => {
 
   // Watch for changes in config files
   browsersync()
-    .watch('config*.js')
+    .watch('{maizzle.config*,config*}.{js,cjs}')
     .on('change', async file => {
-      const parsedEnv = path.parse(file).name.split('.')[1] || 'local'
+      const fileName = path.parse(file).base
+      const match = fileName.match(/\.?config\.(.+?)\./)
+
+      const parsedEnv = match ? match[1] : env || 'local'
 
       Config
         .getMerged(parsedEnv)
@@ -180,7 +183,13 @@ const serve = async (env = 'local', config = {}) => {
           },
           tunnel: false,
           ui: {port: 3001},
-          logFileChanges: false
+          logFileChanges: false,
+          watchOptions: {
+            awaitWriteFinish: {
+              stabilityThreshold: 150,
+              pollInterval: 25
+            }
+          }
         },
         get(config, 'build.browsersync', {})
       ), () => {})
diff --git a/src/generators/config.js b/src/generators/config.js
index 934fd5a..5020c87 100644
--- a/src/generators/config.js
+++ b/src/generators/config.js
@@ -1,6 +1,17 @@
 const path = require('path')
 const {merge, requireUncached} = require('../utils/helpers')
 
+const baseConfigFileNames = [
+  './maizzle.config.js',
+  './maizzle.config.cjs',
+  './maizzle.config.local.js',
+  './maizzle.config.local.cjs',
+  './config.js',
+  './config.cjs',
+  './config.local.js',
+  './config.local.cjs'
+]
+
 module.exports = {
   getMerged: async (env = 'local') => {
     if (typeof env !== 'string') {
@@ -10,17 +21,19 @@ module.exports = {
     let baseConfig = {env}
     let envConfig = {env}
 
-    const cwd = env === 'maizzle-ci' ? './test/stubs/config' : process.cwd()
+    const cwd = ['maizzle-ci', 'test'].includes(env) ? './test/stubs/config' : process.cwd()
 
-    for (const module of ['./config', './config.cjs', './config.local', './config.local.cjs']) {
+    for (const module of baseConfigFileNames) {
       try {
         baseConfig = merge(baseConfig, requireUncached(path.resolve(cwd, module)))
       } catch {}
     }
 
-    if (typeof env === 'string' && env !== 'local') {
+    if (env !== 'local') {
       let loaded = false
-      for (const module of [`./config.${env}`, `./config.${env}.cjs`]) {
+      const modulesToTry = [`./maizzle.config.${env}.js`, `./maizzle.config.${env}.cjs`, `./config.${env}.js`, `./config.${env}.cjs`]
+
+      for (const module of modulesToTry) {
         try {
           envConfig = merge(envConfig, requireUncached(path.resolve(cwd, module)))
           loaded = true
@@ -29,7 +42,7 @@ module.exports = {
       }
 
       if (!loaded) {
-        throw new Error(`could not load config.${env}.js`)
+        throw new Error(`Failed to load config file for \`${env}\` environment, do you have one of these files in your project root?\n\n${modulesToTry.join('\n')}`)
       }
     }
 


Test patch:
diff --git a/test/stubs/config/maizzle.config.test.js b/test/stubs/config/maizzle.config.test.js
new file mode 100644
index 0000000..bf4b41a
--- /dev/null
+++ b/test/stubs/config/maizzle.config.test.js
@@ -0,0 +1,11 @@
+module.exports = {
+  file: 'maizzle.config.test.js',
+  build: {
+    templates: {
+      source: '../templates',
+      destination: {
+        path: 'build_test'
+      }
+    }
+  }
+}
diff --git a/test/test-config.js b/test/test-config.js
index 9fc3c03..b1bc7a5 100644
--- a/test/test-config.js
+++ b/test/test-config.js
@@ -15,5 +15,10 @@ test('throws if env name is not a string', async t => {
 test('throws if a config could not be loaded for the specified environment', async t => {
   await t.throwsAsync(async () => {
     await Config.getMerged('fake')
-  }, {instanceOf: Error, message: `could not load config.fake.js`})
+  }, {instanceOf: Error, message: `Failed to load config file for \`fake\` environment, do you have one of these files in your project root?\n\n./maizzle.config.fake.js\n./maizzle.config.fake.cjs\n./config.fake.js\n./config.fake.cjs`})
+})
+
+test('supports maizzle.config.js file names', async t => {
+  const config = await Config.getMerged('test')
+  t.is(config.file, 'maizzle.config.test.js')
 })
diff --git a/test/test-todisk.js b/test/test-todisk.js
index 4c8cf7c..da37b62 100644
--- a/test/test-todisk.js
+++ b/test/test-todisk.js
@@ -17,7 +17,7 @@ test.afterEach.always(async t => {
 test('throws if config cannot be computed', async t => {
   await t.throwsAsync(async () => {
     await Maizzle.build('missing')
-  }, {instanceOf: Error, message: `could not load config.missing.js`})
+  }, {instanceOf: Error})
 })
 
 test('skips if no templates found', async t => {