Permalink
Browse files

Copied Bundler VS.NET extension into NuGet package folder.

INCR to v1.10. Updated README.md
  • Loading branch information...
1 parent 22a31e1 commit 90da63c23876ade11d0e3eab447c9ed14ba2fb58 @mythz mythz committed Jul 3, 2012
View
2 NuGet/bundler.nuspec
@@ -2,7 +2,7 @@
<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>Bundler</id>
- <version>1.0.3</version>
+ <version>1.1.0</version>
<authors>Demis Bellot</authors>
<owners>Demis Bellot</owners>
<summary>CoffeeScript, JavaScript, Less, Sass, Css compiler, minifier and combiner for ASP.NET MVC websites.</summary>
View
153 NuGet/content/bundler/bundler.js
@@ -22,11 +22,39 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
+function clone(o) {
+ var ret = {};
+ Object.keys(o).forEach(function (val) {
+ ret[val] = o[val];
+ });
+ return ret;
+}
+String.prototype.startsWith = function (str){
+ return this.indexOf(str) === 0;
+};
+String.prototype.endsWith = function (suffix) {
+ return this.indexOf(suffix, this.length - suffix.length) !== -1;
+};
+String.prototype.endsWithAny = function (endings) {
+ var str = this;
+ return endings.some(function (ending) { return str.endsWith(ending); });
+}
+
//recursively scans the directory below for *.js.bundle and *.css.bundle files
-var SCAN_ROOT_DIRS = process.argv.splice(2); //directories specified in bundler.cmd
+var commandLineArgs = process.argv.splice(2); //directories specified in bundler.cmd
+
+var commandLineOptions = commandLineArgs.filter(function (arg) { return arg.startsWith('#'); });
+var defaultOptions = {};
+commandLineOptions.forEach(function (option) {
+ while (option.startsWith('#')) { option = option.substring(1); }
+ var parts = option.split(':');
+ defaultOptions[parts[0].toLowerCase()] = parts.length > 1 ? parts[1] : true;
+});
+
+var SCAN_ROOT_DIRS = commandLineArgs.filter(function (arg) { return !arg.startsWith('#'); });
if (!SCAN_ROOT_DIRS.length) {
console.log("No directories were specified.");
- console.log("Usage: bundler.cmd ../Content ../Scripts");
+ console.log("Usage: bundler.js [#option:value] ../Content [../Scripts]");
return;
}
@@ -41,12 +69,6 @@ var fs = require("fs"),
Step = require('step'),
startedAt = Date.now();
-String.prototype.startsWith = function (str){
- return this.indexOf(str) === 0;
-};
-String.prototype.endsWith = function (suffix) {
- return this.indexOf(suffix, this.length - suffix.length) !== -1;
-};
var walk = function (dir, done) {
var results = [];
@@ -96,6 +118,18 @@ function scanDir(allFiles, cb) {
var jsBundles = allFiles.filter(function (file) { return file.endsWith(".js.bundle"); });
var cssBundles = allFiles.filter(function (file) { return file.endsWith(".css.bundle"); });
+ function getOptions(fileLines) {
+ var options = clone(defaultOptions);
+ if (fileLines.length === 0) return options;
+ var optionsString = fileLines[0];
+ if (!optionsString.startsWith('#options ')) return options;
+ optionsString.substring(9).split(',').forEach(function (option) {
+ var parts = option.split(':');
+ options[parts[0].toLowerCase()] = parts.length > 1 ? parts[1] : true;
+ });
+ return options;
+ };
+
Step(
function () {
var next = this;
@@ -107,11 +141,23 @@ function scanDir(allFiles, cb) {
next();
};
function processBundle(jsBundle) {
- var bundleDir = path.dirname(jsBundle);
+ var bundleDir = path.dirname(jsBundle);
var bundleName = jsBundle.replace('.bundle', '');
readTextFile(jsBundle, function (data) {
var jsFiles = removeCR(data).split("\n");
- processJsBundle(jsBundle, bundleDir, jsFiles, bundleName, nextBundle);
+ var options = getOptions(jsFiles);
+ if (options.folder !== undefined) {
+ options.nobundle = true;
+ var recursive = options.folder === 'recursive';
+ jsFiles = allFiles.map(function jsMatches(fileName) {
+ if (!fileName.startsWith(bundleDir)) return '#';
+ if (!fileName.endsWithAny(['.js', '.coffee'])) return '#';
+ if (fileName.endsWithAny(['.min.js'])) return '#';
+ if (!recursive && (path.dirname(fileName) !== bundleDir)) return '#';
+ return fileName.substring(bundleDir.length + 1);
+ });
+ }
+ processJsBundle(options, jsBundle, bundleDir, jsFiles, bundleName, nextBundle);
});
};
nextBundle();
@@ -130,7 +176,19 @@ function scanDir(allFiles, cb) {
var bundleName = cssBundle.replace('.bundle', '');
readTextFile(cssBundle, function (data) {
var cssFiles = removeCR(data).split("\n");
- processCssBundle(cssBundle, bundleDir, cssFiles, bundleName, nextBundle);
+ var options = getOptions(cssFiles);
+ if (options.folder !== undefined) {
+ options.nobundle = true;
+ var recursive = options.folder === 'recursive';
+ cssFiles = allFiles.map(function cssMatches(fileName) {
+ if (!fileName.startsWith(bundleDir)) return '#';
+ if (!fileName.endsWithAny(['.css', '.less', '.sass', '.scss'])) return '#';
+ if (fileName.endsWithAny(['.min.css'])) return '#';
+ if (!recursive && (path.dirname(fileName) !== bundleDir)) return '#';
+ return fileName.substring(bundleDir.length + 1);
+ });
+ }
+ processCssBundle(options, cssBundle, bundleDir, cssFiles, bundleName, nextBundle);
});
};
nextBundle();
@@ -139,12 +197,25 @@ function scanDir(allFiles, cb) {
);
}
-function processJsBundle(jsBundle, bundleDir, jsFiles, bundleName, cb) {
+function getMinFileName(fileName) {
+ var extension = fileName.substring(fileName.lastIndexOf('.'));
+ return fileName.substring(0, fileName.length - extension.length) + ".min" + extension;
+}
+
+function processJsBundle(options, jsBundle, bundleDir, jsFiles, bundleName, cb) {
console.log("\nprocessing " + jsBundle + ":");
+ for (var optionKey in options) {
+ console.log("option: " + optionKey + " -> " + options[optionKey]);
+ }
var allJsArr = [], allMinJsArr = [], index = 0, pending = 0;
var whenDone = function () {
+ if (options.nobundle) {
+ setTimeout(cb, 0);
+ return;
+ }
+
console.log("writing " + bundleName + "...");
var allJs = "", allMinJs = "";
@@ -153,9 +224,11 @@ function processJsBundle(jsBundle, bundleDir, jsFiles, bundleName, cb) {
allMinJs += ";" + allMinJsArr[i] + "\n";
}
- fs.writeFile(bundleName, allJs, function (_) {
- fs.writeFile(bundleName.replace(".js", ".min.js"), allMinJs, cb);
- });
+ var afterBundle = options.skipmin ? cb : function (_) {
+ var minFileName = getMinFileName(bundleName);
+ fs.writeFile(minFileName, allMinJs, cb);
+ };
+ fs.writeFile(bundleName, allJs, afterBundle);
};
jsFiles.forEach(function (file) {
@@ -171,7 +244,7 @@ function processJsBundle(jsBundle, bundleDir, jsFiles, bundleName, cb) {
var filePath = path.join(bundleDir, file),
jsPath = path.join(bundleDir, jsFile),
- minJsPath = jsPath.replace(".js", ".min.js");
+ minJsPath = getMinFileName(jsPath);
var i = index++;
pending++;
@@ -187,22 +260,34 @@ function processJsBundle(jsBundle, bundleDir, jsFiles, bundleName, cb) {
}
},
function (js) {
- getOrCreateMinJs(js, jsPath, minJsPath, function (minJs) {
- allJsArr[i] = js;
+ allJsArr[i] = js;
+ var withMin = function (minJs) {
allMinJsArr[i] = minJs;
-
- if (! --pending) whenDone();
- });
+ if (! --pending) whenDone();
+ };
+ if (options.skipmin) {
+ withMin('');
+ } else {
+ getOrCreateMinJs(js, jsPath, minJsPath, withMin);
+ }
}
);
});
}
-function processCssBundle(cssBundle, bundleDir, cssFiles, bundleName, cb) {
+function processCssBundle(options, cssBundle, bundleDir, cssFiles, bundleName, cb) {
console.log("\nprocessing " + cssBundle + ":");
+ for (var optionKey in options) {
+ console.log("option: " + optionKey + " -> " + options[optionKey]);
+ }
var allCssArr = [], allMinCssArr = [], index = 0, pending = 0;
var whenDone = function () {
+ if (options.nobundle) {
+ setTimeout(cb, 0);
+ return;
+ }
+
console.log("writing " + bundleName + "...");
var allCss = "", allMinCss = "";
@@ -211,9 +296,11 @@ function processCssBundle(cssBundle, bundleDir, cssFiles, bundleName, cb) {
allMinCss += allMinCssArr[i] + "\n";
}
- fs.writeFile(bundleName, allCss, function(_) {
- fs.writeFile(bundleName.replace(".css", ".min.css"), allMinCss, cb);
- });
+ var afterBundle = options.skipmin ? cb : function (_) {
+ var minFileName = getMinFileName(bundleName);
+ fs.writeFile(minFileName, allMinCss, cb);
+ };
+ fs.writeFile(bundleName, allCss, afterBundle);
};
cssFiles.forEach(function (file) {
@@ -231,7 +318,7 @@ function processCssBundle(cssBundle, bundleDir, cssFiles, bundleName, cb) {
var filePath = path.join(bundleDir, file),
cssPath = path.join(bundleDir, cssFile),
- minCssPath = cssPath.replace(".css", ".min.css");
+ minCssPath = getMinFileName(cssPath);
var i = index++;
pending++;
@@ -251,12 +338,16 @@ function processCssBundle(cssBundle, bundleDir, cssFiles, bundleName, cb) {
}
},
function (css) {
- getOrCreateMinCss(css, cssPath, minCssPath, function (minCss) {
- allCssArr[i] = css;
+ allCssArr[i] = css;
+ var withMin = function (minCss) {
allMinCssArr[i] = minCss;
-
- if (! --pending) whenDone();
- });
+ if (! --pending) whenDone();
+ };
+ if (options.skipmin) {
+ withMin('');
+ } else {
+ getOrCreateMinCss(css, cssPath, minCssPath, withMin);
+ }
}
);
});
View
BIN NuGet/content/bundler/vs2010-extension/BundlerRunOnSave.dll
Binary file not shown.
View
61 NuGet/content/bundler/vs2010-extension/BundlerRunOnSave.dll.CodeAnalysisLog.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet type="text/xsl" href="c:\program files (x86)\microsoft visual studio 10.0\team tools\static analysis tools\fxcop\Xml\CodeAnalysisReport.xsl"?>
+<FxCopReport Version="10.0">
+ <Targets>
+ <Target Name="C:\src\Bundler\src\vs\BundlerRunOnSave\bin\Release\BundlerRunOnSave.dll">
+ <Modules>
+ <Module Name="bundlerrunonsave.dll">
+ <Namespaces>
+ <Namespace Name="ServiceStack.BundlerRunOnSave">
+ <Types>
+ <Type Name="BundlerRunOnSavePackage" Kind="Class" Accessibility="Public" ExternallyVisible="True">
+ <Messages>
+ <Message TypeName="TypesThatOwnDisposableFieldsShouldBeDisposable" Category="Microsoft.Design" CheckId="CA1001" Status="Active" Created="2012-07-02 20:19:10Z" FixCategory="DependsOnFix">
+ <Issue Name="DependsOnFix" Certainty="95" Level="CriticalError">Implement IDisposable on 'BundlerRunOnSavePackage' because it creates members of the following IDisposable types: 'SolutionEventsListener'. If 'BundlerRunOnSavePackage' has previously shipped, adding new members that implement IDisposable to this type is considered a breaking change to existing consumers.</Issue>
+ </Message>
+ </Messages>
+ </Type>
+ </Types>
+ </Namespace>
+ </Namespaces>
+ </Module>
+ </Modules>
+ </Target>
+ </Targets>
+ <Rules>
+ <Rule TypeName="TypesThatOwnDisposableFieldsShouldBeDisposable" Category="Microsoft.Design" CheckId="CA1001">
+ <Name>Types that own disposable fields should be disposable</Name>
+ <Description>Types that declare disposable members should also implement IDisposable. If the type does not own any unmanaged resources, do not implement a finalizer on it.</Description>
+ <Resolution Name="DependsOnFix">Implement IDisposable on {0} because it creates members of the following IDisposable types: {1}. If {0} has previously shipped, adding new members that implement IDisposable to this type is considered a breaking change to existing consumers.</Resolution>
+ <Owner />
+ <Url>http://msdn.microsoft.com/library/ms182172(VS.100).aspx</Url>
+ <Email>[none]</Email>
+ <MessageLevel Certainty="95">CriticalError</MessageLevel>
+ <File Name="designrules.dll" Version="10.0.0.0" />
+ </Rule>
+ </Rules>
+ <Localized>
+ <String Key="Category">Category</String>
+ <String Key="Certainty">Certainty</String>
+ <String Key="CollapseAll">Collapse All</String>
+ <String Key="CheckId">Check Id</String>
+ <String Key="Error">Error</String>
+ <String Key="Errors">error(s)</String>
+ <String Key="ExpandAll">Expand All</String>
+ <String Key="Help">Help</String>
+ <String Key="Line">Line</String>
+ <String Key="Messages">message(s)</String>
+ <String Key="LocationNotStoredInPdb">[Location not stored in Pdb]</String>
+ <String Key="Project">Project</String>
+ <String Key="Resolution">Resolution</String>
+ <String Key="Rule">Rule</String>
+ <String Key="RuleFile">Rule File</String>
+ <String Key="RuleDescription">Rule Description</String>
+ <String Key="Source">Source</String>
+ <String Key="Status">Status</String>
+ <String Key="Target">Target</String>
+ <String Key="Warning">Warning</String>
+ <String Key="Warnings">warning(s)</String>
+ <String Key="ReportTitle">Code Analysis Report</String>
+ </Localized>
+</FxCopReport>
View
0 NuGet/content/bundler/vs2010-extension/BundlerRunOnSave.dll.lastcodeanalysissucceeded
No changes.
View
BIN NuGet/content/bundler/vs2010-extension/BundlerRunOnSave.pkgdef
Binary file not shown.
View
BIN NuGet/content/bundler/vs2010-extension/BundlerRunOnSave.vsix
Binary file not shown.
View
BIN NuGet/content/bundler/vs2010-extension/ServiceStack-logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
29 NuGet/content/bundler/vs2010-extension/extension.vsixmanifest
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+ <Identifier Id="be8d8502-0f7a-4142-868c-d78ef3a3ae4b">
+ <Name>Bundler Run on Save</Name>
+ <Author>ServiceStack</Author>
+ <Version>1.0</Version>
+ <Description xml:space="preserve">When you save a .less, .sass, .css, .js, .coffee or .bundle file, this extension will run bundler if it is installed in the project.</Description>
+ <Locale>1033</Locale>
+ <Icon>favicon.ico</Icon>
+ <PreviewImage>ServiceStack-logo.png</PreviewImage>
+ <InstalledByMsi>false</InstalledByMsi>
+ <SupportedProducts>
+ <VisualStudio Version="10.0">
+ <Edition>Ultimate</Edition>
+ <Edition>Premium</Edition>
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ </SupportedProducts>
+ <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.0" />
+ </Identifier>
+ <References>
+ <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
+ <Name>Visual Studio MPF</Name>
+ </Reference>
+ </References>
+ <Content>
+ <VsPackage>BundlerRunOnSave.pkgdef</VsPackage>
+ </Content>
+</Vsix>
View
BIN NuGet/content/bundler/vs2010-extension/favicon.ico
Binary file not shown.
View
41 README.md
@@ -1,13 +1,16 @@
# Bundler
-Bundler is a fast, command-line tool (easily integrated into existing IDEs, inc VS.NET) that statically **compiles**, **minifies** and **combines** your websites **less**, **sass**, **css**, **coffeescript** and **js** files.
+Bundler is a fast, cross-platform, command-line runner (easily integrated into existing IDEs, inc VS.NET) with optimized support for ASP.NET MVC that statically **compiles**, **minifies** and **combines** your websites **less**, **sass**, **css**, **coffeescript** and **js** files.
- - All bundling is done at **compile time** with a build-step so no dependencies needed at runtime.
- - Can be used with any website project (ie. not only .NET). Includes a **windows** node.exe although all scripts work cross-platform.
- - Includes a single C# **MvcBundler.cs** class with extension methods to seamlessly integrate it with any **ASP.NET MVC** website.
- - Runs outside the context of your ASP.NET MVC website so client scripts can be re-compiled **without restarting** your C# project.
- - Uses a self-contained **node.exe** for all compilation & minification - designed for maximum runtime and compile time performance.
- - Doesn't use any compiled dlls or .exe's (excl node.exe) and includes source code for everything so can easily be read and extended.
+Bundler uses the popular and well-tested javascript libraries in [node's package manager](http://npmjs.org/) for all minification and compilation. This enables it to generate faster and more up-to-date outputs than any other .NET wrapper solution which either uses old .NET ports of node.js or ruby implementations, or they have to invoke external out-of-process [IronRuby](http://www.ironruby.net/) and JavaScript processes resulting in slower execution - consuming valuable iteration-time on each dev-cycle.
+
+ - It's easy to use! all `.bundle` files are plain text files which just lists the file names that make up each bundle
+ - All bundling is done at **compile time** with a build-step so no dependencies needed at runtime
+ - Can be used with any website project (ie. not only .NET). Includes a **windows** node.exe although all scripts work cross-platform
+ - Includes a single C# **MvcBundler.cs** class with extension methods to seamlessly integrate it with any **ASP.NET MVC** website
+ - Runs outside the context of your ASP.NET MVC website so client scripts can be re-compiled **without restarting** your C# project
+ - Uses a self-contained **node.exe** for all compilation & minification - designed for maximum runtime and compile time performance
+ - Doesn't use any compiled dlls or .exe's (excl node.exe) and includes source code for everything so can easily be read and extended
## Extremely fast at both Build and Runtime
Bundler is extremely fast - uses Googles leading V8 JavaScript engine (inside node.exe). All build scripts use only *pure JavaScript* implementations (uglifyjs, coffee-script, clean-css, etc) allowing all compilation and minification to run in a single process.
@@ -27,6 +30,9 @@ To run you just need a copy of **/bundler** folder in your website host director
*Once installed you can optionally exclude the '/bundler' or '/bundler/node_modules' folders from your VS.NET project since they contain a lot of files (not required to be referenced).*
+#### Installing the VS.NET 2010 Extension
+If you have VS.NET 2010 you should also install the local `bundler\vs2010-extension\BundlerRunOnSave.vsix` VS.NET extension which automatically runs bundler for you when any .less, .css, .sass, .js, .coffee and .bundle file is saved.
+
By default bundler looks at **/Content** and **/Scripts** project folders - this can be changed by editing [/bundler/bundler.cmd](https://github.com/ServiceStack/Bundler/blob/master/NuGet/content/bundler/bundler.cmd):
node bundler.js ../Content ../Scripts
@@ -59,20 +65,21 @@ Now everytime you run **/bundler/bundler.cmd** it will scan these files, compili
## Running Bundler
You basically want to run Bundler when a file your website references has changed, so you can see those changes before your next page refresh.
-Although `bundler.cmd` is just a simple command-line script, there are multiple ways you can run it during development:
+Although `bundler.cmd` is just a simple command-line script, there are a few different ways you can run it during development (in order of most productive):
- - Automatically on save of a .less, .css, .sass, .js, .coffee and .bundle (after the VS.NET Extension is installed)
- - Create an **External Tool** inside VS.NET that runs `bundler.cmd`
- - Optionally assign it a short-cut so you can run it with a single key-stroke
- - As a Post-Build event in your project, to run it at the end of every build
+ 1. Automatically on save of a .less, .css, .sass, .js, .coffee and .bundle (after the 2010 VS.NET Extension is installed)
+ 2. Create an **External Tool** inside VS.NET that runs `bundler.cmd`. Optionally assign it a short-cut so you can run it with a single key-stroke.
+ 3. As a Post-Build event in your project, to run it at the end of every build
-Note: If your team doesn't check-in compiled or minified files you should also have your CI build agents run `bundler.cmd` after each build.
+**Reminder:** If you don't check-in compiled or .min files you should also get your CI build agents run `bundler.cmd` after each build.
### Bundler Run on Save Visual Studio Extension
-The Bundler Run on Save extension executes bundler if it is included in the project folder when you save any file in the project with an allowed extension. The file extensions which trigger this are: .less, .css, .sass, .js, .coffee and .bundle.
+After you install bundler from the nuget package, double-click the `bundler\vs2010-extension\BundlerRunOnSave.vsix` VS.NET extension to add it to VS.NET - rebooting VS.NET maybe required for the changes to take effect:
+
+![Bundler VS.NET Extension installer](http://www.servicestack.net/files/BundlerRunOnSave.png)
-If you install bundler from the nuget package, this extension should just work. The bundler directory does not have to be in the project, it just has to exist in the same folder as the project file. When the extension runs bundler, you can see the output in a new Bundler pane of the Output window.
+Once installed the **BundlerRunOnSave.vsix** VS.NET extension runs bundler when you save any file in the project with any of the supported extensions .less, .css, .sass, .js, .coffee and .bundle.
### Create an External Tool inside VS.NET:
@@ -165,6 +172,10 @@ Tip: If you just want bundler to transform all the files in your content folder,
#options folder:recursive
+## Development
+
+The Bundler VS.NET extension lives in [/src/vs/BundlerRunOnSave](https://github.com/ServiceStack/Bundler/blob/master/src/vs/BundlerRunOnSave) which requires the VS.NET templates provided by the [Visual Studio 2010 SP1 SDK](http://www.microsoft.com/en-us/download/details.aspx?id=21835) in order to open it.
+
## Contributors
A big thanks to all of Bundler's contributors:
View
3 build/copy.bat
@@ -49,3 +49,6 @@ COPY %FROM%\node_modules\step\package.json %DIST%\node_modules\step
COPY %FROM%\node_modules\step\lib\* %DIST%\node_modules\step\lib
COPY %FROM%\node_modules\uglify-js.js %DIST%\node_modules
+
+MD %DIST%\vs2010-extension
+COPY %FROM%\vs\BundlerRunOnSave\bin\Release\* %DIST%\vs2010-extension

0 comments on commit 90da63c

Please sign in to comment.