diff --git a/README.md b/README.md
index 8d7e9cef..896bbaa7 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ for changes and roadmap.
### Getting started
-Right-click any `.less`, `.scss`, `.styl`, `.jsx`, `.es6` or `.coffee` file in Solution Explorer to
+Right-click any `.less`, `.scss`, `.styl`, `.jsx`, `.es6`, `.coffee`, or `.css` file in Solution Explorer to
setup compilation.

@@ -46,7 +46,7 @@ run all the configured compilers.
### Compile on save
-Any time a `.less`, `.scss`, `.styl`, `.jsx`, `.es6` or `.coffee` file is modified within
+Any time a `.less`, `.scss`, `.styl`, `.jsx`, `.es6`, `.coffee`, or `.css` file is modified within
Visual Studio, the compiler runs automatically to produce the compiled output file.
The same is true when saving the `compilerconfig.json` file where
@@ -133,7 +133,18 @@ Here's an example of what that file looks like:
"options":{
"sourceMap": true
}
+ },
+ {
+ "outputFile": "output/tailwind.css",
+ "inputFile": "input/tailwind.css",
+ "minify": {
+ "enabled": true
+ },
+ "includeInProject": true,
+ "options":{
+ "sourceMap": true
+ }
}
]
```
-Default values for `compilerconfig.json` can be found in the `compilerconfig.json.defaults` file in the same location.
\ No newline at end of file
+Default values for `compilerconfig.json` can be found in the `compilerconfig.json.defaults` file in the same location.
diff --git a/src/WebCompiler/Compile/CompilerService.cs b/src/WebCompiler/Compile/CompilerService.cs
index 119b7ff0..f16c3303 100644
--- a/src/WebCompiler/Compile/CompilerService.cs
+++ b/src/WebCompiler/Compile/CompilerService.cs
@@ -15,7 +15,7 @@ public static class CompilerService
private static object _syncRoot = new object(); // Used to lock on the initialize step
/// A list of allowed file extensions.
- public static readonly string[] AllowedExtensions = new[] { ".LESS", ".SCSS", ".SASS", ".STYL", ".COFFEE", ".ICED", ".JS", ".JSX", ".ES6", ".HBS", ".HANDLEBARS" };
+ public static readonly string[] AllowedExtensions = new[] { ".LESS", ".SCSS", ".SASS", ".STYL", ".COFFEE", ".ICED", ".JS", ".JSX", ".ES6", ".HBS", ".HANDLEBARS", ".CSS" };
///
/// Test if a file type is supported by the compilers.
@@ -67,6 +67,10 @@ internal static ICompiler GetCompiler(Config config)
case ".ES6":
compiler = new BabelCompiler(_path);
break;
+
+ case ".CSS":
+ compiler = new TailwindCompiler(_path);
+ break;
}
return compiler;
diff --git a/src/WebCompiler/Compile/TailwindCompiler.cs b/src/WebCompiler/Compile/TailwindCompiler.cs
new file mode 100644
index 00000000..aa383077
--- /dev/null
+++ b/src/WebCompiler/Compile/TailwindCompiler.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace WebCompiler
+{
+ class TailwindCompiler : ICompiler
+ {
+ private static Regex _errorRx = new Regex(@".+\.css:\s(?.+)\((?[0-9]+):(?[0-9]+)\)", RegexOptions.Compiled);
+ private string _path;
+ private string _output = string.Empty;
+ private string _error = string.Empty;
+
+ public TailwindCompiler(string path)
+ {
+ _path = path;
+ }
+
+ public CompilerResult Compile(Config config)
+ {
+ string baseFolder = Path.GetDirectoryName(config.FileName);
+ string inputFile = Path.Combine(baseFolder, config.InputFile);
+
+ FileInfo info = new FileInfo(inputFile);
+ string content = File.ReadAllText(info.FullName);
+
+ CompilerResult result = new CompilerResult
+ {
+ FileName = info.FullName,
+ OriginalContent = content,
+ };
+
+ try
+ {
+ RunCompilerProcess(config, info);
+
+ result.CompiledContent = _output;
+
+ if (_error.Length > 0)
+ {
+ CompilerError ce = new CompilerError
+ {
+ FileName = info.FullName,
+ Message = _error.Replace(baseFolder, string.Empty),
+ IsWarning = !string.IsNullOrEmpty(_output)
+ };
+
+ var match = _errorRx.Match(_error);
+
+ if (match.Success)
+ {
+ ce.Message = match.Groups["message"].Value.Replace(baseFolder, string.Empty);
+ ce.LineNumber = int.Parse(match.Groups["line"].Value);
+ ce.ColumnNumber = int.Parse(match.Groups["column"].Value);
+ }
+
+ result.Errors.Add(ce);
+ }
+ }
+ catch (Exception ex)
+ {
+ CompilerError error = new CompilerError
+ {
+ FileName = info.FullName,
+ Message = string.IsNullOrEmpty(_error) ? ex.Message : _error,
+ LineNumber = 0,
+ ColumnNumber = 0,
+ };
+
+ result.Errors.Add(error);
+ }
+
+ return result;
+ }
+
+ private void RunCompilerProcess(Config config, FileInfo info)
+ {
+ string arguments = ConstructArguments(config);
+
+ ProcessStartInfo start = new ProcessStartInfo
+ {
+ WorkingDirectory = info.Directory.FullName,
+ UseShellExecute = false,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ CreateNoWindow = true,
+ FileName = "cmd.exe",
+ Arguments = $"/c \"\"{Path.Combine(_path, "node_modules\\.bin\\tailwind.cmd")}\" {arguments} \"{info.FullName}\"\"",
+ StandardOutputEncoding = Encoding.UTF8,
+ StandardErrorEncoding = Encoding.UTF8,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ };
+
+ start.EnvironmentVariables["PATH"] = _path + ";" + start.EnvironmentVariables["PATH"];
+
+ using (Process p = Process.Start(start))
+ {
+ var stdout = p.StandardOutput.ReadToEndAsync();
+ var stderr = p.StandardError.ReadToEndAsync();
+ p.WaitForExit();
+
+ _output = stdout.Result;
+ _error = stderr.Result;
+ }
+ }
+
+ private static string ConstructArguments(Config config)
+ {
+ string arguments = "build";
+
+ var options = TailwindOptions.FromConfig(config);
+
+ if (options.SourceMap || config.SourceMap)
+ arguments += " --source-maps";
+
+ return arguments;
+ }
+ }
+}
diff --git a/src/WebCompiler/Config/ConfigHandler.cs b/src/WebCompiler/Config/ConfigHandler.cs
index 5b827bde..955bf2c7 100644
--- a/src/WebCompiler/Config/ConfigHandler.cs
+++ b/src/WebCompiler/Config/ConfigHandler.cs
@@ -68,6 +68,7 @@ public void CreateDefaultsFile(string fileName)
babel = new BabelOptions(),
coffeescript = new IcedCoffeeScriptOptions(),
handlebars = new HandlebarsOptions(),
+ tailwindcss = new TailwindOptions(),
},
minifiers = new
{