Repository: tailwindlabs/tailwindcss
Pull request #1861 (2020-05-30 17:06:22)

Allows users to use "tailwind build" without requiring an input file
Hi,

This has cropped up a handful of times throughout Discord, and the solution is pretty simple to add to the Tailwind CLI core, however for less experienced users without knowledge of creating Node scripts and using the PostCSS API it's a little more complicated.

Effectively a handful of people have wanted to just generate the .css file based off their config, without having to create an additional .css entry point file which won't be used for anything.

With this in mind this PR allows users to omit the `<file>` param - If they do not pass in an entry file it will fall back to generate the output based off:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

Example usage would be:

```shell
npx tailwind build -o styles.css
```

Might be handy 🤷🏻‍♂️ What do people think?

(P.S. - PR needs cleaning up, e.g. eslint etc - didn't want to spend the time if people don't like the idea of this)


Patch:
diff --git a/src/cli/commands/build.js b/src/cli/commands/build.js
index 6d79b48f..0eeb11f7 100644
--- a/src/cli/commands/build.js
+++ b/src/cli/commands/build.js
@@ -80,7 +80,11 @@ function buildToFile(compileOptions, startTime) {
 
   utils.header()
   utils.log()
-  utils.log(emoji.go, 'Building...', colors.file(inputFileSimplePath))
+  utils.log(
+    emoji.go,
+    'Building...',
+    colors.file(inputFileSimplePath || 'defaults: @base, @components and @utilities.')
+  )
 
   return compile(compileOptions).then(result => {
     utils.writeFile(compileOptions.outputFile, result.css)
@@ -112,8 +116,9 @@ export function run(cliParams, cliOptions) {
     const inputFileSimplePath = utils.getSimplePath(inputFile)
     const configFileSimplePath = utils.getSimplePath(configFile)
 
-    !inputFile && stopWithHelp('CSS file is required.')
-    !utils.exists(inputFile) && stop(colors.file(inputFileSimplePath), 'does not exist.')
+    if (inputFile) {
+      !utils.exists(inputFile) && stop(colors.file(inputFileSimplePath), 'does not exist.')
+    }
 
     configFile &&
       !utils.exists(configFile) &&
diff --git a/src/cli/compile.js b/src/cli/compile.js
index 956d5e78..dcfc6408 100644
--- a/src/cli/compile.js
+++ b/src/cli/compile.js
@@ -25,7 +25,14 @@ const defaultOptions = {
  */
 export default function compile(options = {}) {
   const config = { ...defaultOptions, ...options }
-  const css = utils.readFile(config.inputFile)
+
+  const css = config.inputFile
+    ? utils.readFile(config.inputFile)
+    : `
+    @tailwind base;
+    @tailwind components;
+    @tailwind utilities;
+  `
 
   return new Promise((resolve, reject) => {
     postcss(config.plugins)


Test patch:
diff --git a/__tests__/cli.test.js b/__tests__/cli.test.js
index e8b93723..d1c7149b 100644
--- a/__tests__/cli.test.js
+++ b/__tests__/cli.test.js
@@ -43,12 +43,20 @@ describe('cli', () => {
   })
 
   describe('build', () => {
-    it('compiles CSS file', () => {
+    it('compiles CSS file using an input css file', () => {
       return cli(['build', inputCssPath]).then(() => {
         expect(process.stdout.write.mock.calls[0][0]).toContain('.example')
       })
     })
 
+    it('compiles CSS file without an input css file', () => {
+      return cli(['build']).then(() => {
+        expect(process.stdout.write.mock.calls[0][0]).toContain('normalize.css') // base
+        expect(process.stdout.write.mock.calls[0][0]).toContain('.container') // components
+        expect(process.stdout.write.mock.calls[0][0]).toContain('.mx-auto') // utilities
+      })
+    })
+
     it('compiles CSS file using custom configuration', () => {
       return cli(['build', inputCssPath, '--config', customConfigPath]).then(() => {
         expect(process.stdout.write.mock.calls[0][0]).toContain('400px')