I would like to use ServiceStack as a pure AppHost implementation without using MVC. I want to use it to drive a Single Page App.
Serving the SPA's single HTML shell page is straightforward enough and I've found plenty of examples on doing that. However, I also need to serve a number of JavaScript files and I'm assessing the best way of doing this. I can simply put script tags in the HTML shell page but then I don't get the benefits of bundling and minification, and I would have to maintain this every time I add a new JavaScript file.
All these problems are solved with bundling solutions such as Cassette or ASP.NET MVC4 Bundles. But how would I use these with ServiceStack AppHost?
The ServiceStack.Bundler project is great but it seems to have dependencies on ASP.NET MVC, e.g. as a base for the HTML Helpers which render the JavaScript tags in the HTML.
I'd like to be able to do this without any dependency on MVC, if possible.
If you haven't taken a look at GruntJS yet, it's worth a look (http://gruntjs.com/). By creating some simple tasks, it can combine & minify your HTML, JS, and CSS and has no dependency on .NET. There are a lot of other really useful tasks available to GruntJS as well (js lint checks, JS unit test running, and tons more). You can easily setup different tasks for your environments as well (ie, don't combine/minify when deploying to dev server).
What it allows you to do is create a purely static HTML, CSS, and JS SPA, and you can manage that in a completely different solution/project than your ServiceStack AppHost.
So in your example, you'd just reference the scripts in your index.html file like you normally would and when you're ready to deploy to staging/production you'd run your grunt task which would bundle/minify your code for you and output the static html, min.css, and min.js files for you to some deployment directory. It's really powerful and flexible.
I used to use Bundler and I recently made the switch to GruntJS and I haven't looked back.
So, I don' think there is anything to need to do within ServiceStack's AppHost to use a 'bundling-and-minification' solution. To simplify the 'Bundling' process...
1 - 'Bundle' files from a folder(s) creating a new file(s)
2 - Reference the 'Bundled' file(s) from a View/Html
How to 'Bundle' files from a folder(s) creating a new file(s)
Cassette
Cassette seems to handle this process with 'some magic' (see web.config modifications for insight) that calls the Configure method of the CassetteBundleConfiguration class. Installing the Nuget package takes care of 'setup' for you.
ServiceStack.Bundler
ServiceStack.Bundler has a few different ways to handle this process...1) Manually with bundler.cmd, 2) A VS extension 3) Post Build Script 4) Short-cut key to an External Tool
Reference the 'Bundled' file(s)
You can do this however you like as long as you know the path of the file(s)
<link href="/Content/some.css" rel="stylesheet" type="text/css" />
<script src='some.js'></script>
Cassette offers some convenient rendering features
#Bundles.Reference('yourbundle')
#Bundles.RenderStylesheets()
#Bundles.RenderScripts()
ServiceStack.Bundler offers some as well (I think this is the code the depends on System.Web.MVC)
#Html.RenderJsBundle()
#Html.RenderCssBundle()
Note: These are just writing out the <link> and <script> HTML tags.
It seems neither Cassette nor Microsoft.AspNet.Web.Optimization (the bundling solution included with MVC4 projects by default) have dependencies on ASP.NET MVC. Therefore either solution can be made to work with an AppHost implementation of ServiceStack.
For Cassette:
It all works just fine if, from NuGet, you install:
ServiceStack.Host.AspNet
ServiceStack.Razor
Cassette.Aspnet
... and then use Cassette from a Razor 'cshtml' file as usual.
One small gotcha which did cause me to scratch my head for a few minutes:
The order in which the HttpHandlers are listed in your web.config is important. The ServiceStack.Host.AspNet package adds an HttpHandler path which uses a wildcard meaning any further HttpHandlers, such as that for Cassette.axd, are never reached.
Simply changing the order in my web.config from:
<httpHandlers>
<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
<add path="cassette.axd" verb="*" type="Cassette.Aspnet.CassetteHttpHandler, Cassette.Aspnet" />
</httpHandlers>
to:
<httpHandlers>
<add path="cassette.axd" verb="*" type="Cassette.Aspnet.CassetteHttpHandler, Cassette.Aspnet" />
<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
fixed the problem. I don't know if installing Cassette.Aspnet from Nuget first would have prevented this issue from occurring in the first place.
For Microsoft.AspNet.Web.Optimization:
From NuGet, you install:
ServiceStack.Host.AspNet
ServiceStack.Razor
Microsoft.AspNet.Web.Optimization
Having done this, you can use Microsoft.AspNet.Web.Optimization bundling and minification as normal.
I added a BundleConfig.cs file, followng the convention you'd find in a default MVC4 project. I then call BundleConfig.RegisterBundles(BundleTable.Bundles); from the ServiceStack AppHost file.
Thereafter, all #Scripts.Render() statements in Razor files work just fine.
Related
I am using VS 2015 + ASP.net vnext + Angular 2 + Typescript + gulp.js. I have automated my scripts/**/*.ts files moving to the wwwroot/app folder. Now I want to do the same for my libraries like Angular 2. I want that a gulp process injects
angular.js inside index.html inside the <environment names="Development"> node;
angular.min.js inside index.html inside the <environment names="Production"> node.
Of course I want that this to happen for all my libs automatically, without having knowledge about a library:
<any>.min.js (production)
<any>.js (development)
The minification of any.js can be done by me.
Actually I would just have to regard all dependencies in package.json... but then I am lost.
Can my idea be done or does there maybe already exist a tool? Or should the workflow broken into more manual steps like I have to copy/paste a certain library?
Or is it possible to take the dependencies name and concat it with .js then search this file under the node_modules folder... (kind of hacky and not safe...)
UPDATE
Rephrase/Refine my question:
How can I automatically add my npm dependencies (not devDependencies) to the environment "Development" node when triggering a certain event like build/clear/etc...
There is a little tag helper for this, called asp-src-include.
Imagine the case where you have a handful of *.js files you want to include:
<script src="/app/app.js"></script>
<script src="/app/controller/controllerA.js"></script>
<script src="/app/controller/controllerB.js"></script>
<script src="/app/service/userservice.js"></script>
etc. You can include all of these with a single `ยด tag.
<script asp-src-include="~/app/**/*.js"></script>
So for Production/Development deployment your Razor markup may look like
<environment names="Development">
<script asp-src-include="~/app/**/*.js"></script>
</environment>
<environment names="Staging,Production">
<script asp-src-include="~/app/**/*.min.js"></script>
</environment>
For this you need the #addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" (starting with RC1 or RC2 it's ' #addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers' - without the double-quotes ) declaration in your *.cshtml files or inside your _Layout.cshtml.
edit
There is an module called gulp-npm-files that does something similar, it copies all *.js files into the target folders. You can see it's source on GitHub in case you want write your own module to extend the functionality.
But that may not be exactly what you want, as the folders often contain multiple files, for example angular2 (AngularJS 2.0) contains dozen of files (*.js and *.ts), but you're mostly only interested in the compiled/minified ones, found in angular2/bundles/* like angular2.js, angular2.min.js or angular.dev.js.
The package.json of the particular dependency provides no information on where to find this compiled files. So I guess, there's no way to automate this unless you want to copy all of the files to wwwroot which makes no sense in my eyes, especially if you want to use asp-src-include, as it makes no difference on what it includes, so you want to minimize the number of *.js files in your wwwroot folder.
I guess the best you can do is to manually copy the dependencies via gulp task and then use asp-src-include to automatically include them into your razor generated html files.
So your problem is that you want to inject the scripts automatically into your HTML, right? You can use the Wiredep module for that.
And for copying the assets to an other folder, there are many modules to copy or link files from one folder to another. Gulp-copy is the first one i could find.
I'm going to use .less in my css.
Based on my understanding there different kind of way to use .less.
you can pre-compile it then use the css generated by .less
another one is using this scripts below:
This
<link rel="stylesheet/less" type="text/css" href="style.less">
<script src="less.js" type="text/javascript"></script>
or
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.7.3/less.min.js"></script>
as for my understanding it doesn't need the css file because it will generate one for itself once it runs.
I've already installed Web Essentials and it is easy to follow number 1 because it generates the file already when you save it or build it. However, I'm planning to use number 2.
I've read: "Web Essentials uses the node-less compiler and it always uses the latest version" so I don't think I need to install anything.
When I run it i got this error:
FileError: _http://localhost:xxxxxx/Content/style.less wasn't found (404)
Actually, the VS intellisense can't even find the .less file when I put it in href="" so I code it anyway.
I've already look into these no one setup in Visual Studio Web Essentials.
http://verekia.com/less-css/dont-read-less-css-tutorial-highly-addictive
http://www.sitepoint.com/a-comprehensive-introduction-to-less/
http://webdesign.tutsplus.com/articles/get-into-less-the-programmable-stylesheet-language--webdesign-5216
http://lesscss.org/#using-less
It's because IIS doesn't know what a .less file is and therefore won't serve it. You need to add the following to your web.config's <system.webServer> section:
<staticContent>
<remove fileExtension=".less" />
<mimeMap fileExtension=".less" mimeType="text/css" />
</staticContent>
Try to use this tutorial. You have to include your css file. Some tools like Koala generate your css file to output folder ( Web Essentials do it too).
You have to include generated css.
If you are using less.js you have to set options in server side (that you see in this webpage).
dotless
I'm planning to use number 2.
I would definitely advise against using the less.js file as a script on your page. This will slow your page down as you have to download the js file and then it has to process your less file. As you are using Visual Studio and Web Essentials this is totally unnecessary, it will compile the CSS file for you.
Web Essentials automatically compiles a CSS file for you either on save or build depending on your settings. All you then need to do is add the CSS file to your page and NOT the less file.
<link rel="stylesheet" type="text/css" href="styles.css">
More info on settings within Web Essentials for less can be found on the Web Essentials site.
Less features
I have a .LESS stylesheet, I found a way to change variables value throw JavaScript with an old modified version of less.js
https://github.com/hbi99/less.js/commit/6508fe89a6210ae3cd8fffb8e998334644e7dcdc)
the problem is that worked well on the designing stage because I was compiling the .LESS with the browser, now I'm building the site with asp.net, I decided to use dotless, the problem with compiling the .LESS file in the server is that dynamic variables convert to static, delete my variables and do not let me change the value throw JS.
The question is, Is there a way to say asp.net that the .LESS file must be compiled by the browser on the client?
Because just importing the .LESS file and the JS file in my html page doesn't work,
<link href="~/Content/css/UI.less" rel="stylesheet/less" type="text/css" />
the browser doesn't find the .LESS file and respond with a 404 HTTP Response.
Does asp.net hide that file or something?
PD: I already tried not adding the dotless dependency to the project which supposedly compile the .LESS file
Well I could find an answer, The only problem of the 404 HTTP response was that IIS does not support the file extension .less with a MYME-Type of stylesheet/less so for security reasons I suppose It hide that for requests, and what I had to do was configure that con the console like...
appcmd set config /section:staticContent /+[fileExtension='.less',mimeType='text/css']
Use dotless if your want the server to compile the LESS stylesheet.
Use the less.js file if you want to compile in the browser.
Also, instead of the appcmd command you can tell Web.config that your application will serve .less files
<staticContent>
<remove fileExtension=".less" />
<mimeMap fileExtension=".less" mimeType="text/css" />
</staticContent>
This way, you don't have to run appcmd if you deploy your code to another machine.
I'm using Grunt to compile jade templates to html, uglify/concat js and minimize/concat css.
During development I use the combination of connect and watch to serve my front-end and pick up changes automatically. In this I also use the 'source' js and css (and not the uglified/concatted/minified version).
Now when I generate the production html, js and css I wonder what the best solution is to change the inclusions of the *.min js and css.
To be more specific in my html I e.g. include:
a.css
b.css
c.css
a.js
b.js
for development this is fine, but when generating the production version I want:
common-min.css
common-min.js
Of course I don't want to change the Jade templates manually so I'm looking for a better approach, probably with the use of some Grunt plugin.
You can pass data into your template that indicates what environment you are in, and then switch what you're including based on that.
// In your route:
res.render("index", { env: "development" }); // maybe use NODE_ENV in here?
// Then in your jade template:
head
if env == 'development'
link(href="a.css", rel="stylesheet", type="text/css")
link(href="b.css", rel="stylesheet", type="text/css")
else
link(href="min.css", rel="stylesheet", type="text/css")
See the Jade docs, and search for "conditionals": http://jade-lang.com/reference
#Marcel
What you're looking for is a jade build block processor (or more commonly an HTML build block processor). Unfortunately, for jade there only appears to be a gulp plugin, and not one for grunt.
https://www.npmjs.com/package/gulp-processjade
This example may suit your needs.
// build:js app.min.js
script(src='app.js')
// /build
#Jakerella
For each version, a production build is typically run once. So it's more effective to use a build server, task manager, or dependency manager; and less effective to dynamically generate the production version of the HTML page within the server's request handler. Don't use env with res.render() - logic used to build a page for production isn't needed when the entire server is built for production. This production logic also makes the request handler less modular, because it's coupled to the HTML page. Only build servers (ones dedicated to builds) should incorporate build logic. And, while the dynamically generated pages can be cached to avoid the repeated computation in rendering the production version of the HTML page, that's memory overhead that could be avoided.
I am trying to learn Derby.js and I am having a lot of trouble. I know I can include packages such as jQuery through npm and add it to the node_modules folder, but this isn't quite what I want to do. I want to be able to include these files like I do in normal HTML.
So I want to do something like <Head:> <script src="js/jquery.js"></script>. This does not work though because it cannot find the js directory. I expect this has something to do with the way node.js runs an app and that the app itself will not hold the js directory.
Any help would be appreciated!
Derby offers the Script: tag:
<Scripts:>
<script type="text/javascript" src="/components/jquery/jquery.js"></script>
The components directory is because of the usage of bower. Put the components directory into the public directory. According to the express FAQ, the static routes search below the given directory (which is public in derby's example application). Configure bower to put the files under public/components (Choose bower install directory).
The public directory is configured at lib/server/index.js: .use(gzippo.staticGzip(publicPath, {maxAge: ONE_YEAR})), where publicPath is configured above to path.join(root, 'public').
Be aware that the "idea behind the inline script is that it runs immediately, before any of the external scripts are loaded. This should only be used in rare cases where the script should run before the page is displayed in the browser, such as sizing something to the window or autofuocusing an element in browsers that don't support the "autofocus" attribute." Nate Smith in the derby google group.
Inline scripts should be placed in inline.js, located in the same directory as the application's index.js.
If you require jQuery to do something on the loaded page, following code snipped worked at my side (Firefox, Chrome) in inline.js:
window.onload = function() {
alert($(this));
}