I'm migrating a old MVC application to new asp.net core and I'm dealing with the new bundleconfig.json and how it works.
In the old code I used to have something like this:
bundles.Add(new ScriptBundle("~/bundles/appcomponents").Include(
"~/Scripts/js/jquery.js",
"~/Scripts/js/bootstrap.js",
"~/Scripts/js/modernizr.js",
"~/Scripts/js/detect.js",
"~/Scripts/js/fastclick.js",
"~/Scripts/js/jquery.slimscroll.js",
"~/Scripts/js/jquery.blockUI.js",
"~/Scripts/js/waves.js",
"~/Scripts/js/wow.min.js",
"~/Scripts/js/jquery.nicescroll.js",
"~/Scripts/js/jquery.scrollTo.min.js"));
And in my CSHTML file I just added #Scripts.Render("~/bundles/appcomponents")
And I can had multiple bundles so depending on the view I could reference a different bundle depending on the files required for that module or view.
In Asp.Net Core I don't know how to do that.
I saw that you can add the files for CSS and JS but just once, like I don't see a way to have multiple bundles. In that case not all the modules uses the same CSS files and JS files so doesn't make sense to always pulls everything, what it makes more sense is to just use the required files for that module of view and thus from the bundleconfig.json a way to have multiple bundles just as in the old mvc projects.
[
{
"outputFileName": "wwwroot/css/main.min.css",
"inputFiles": [
"wwwroot/css/site.css",
"wwwroot/css/abc01.css"
]
},
{
"outputFileName": "wwwroot/js/main.min.js",
"inputFiles": [
"wwwroot/js/site.js",
"wwwroot/js/abc01.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
Also, if I'm running based on development, can I just reference my script as:
<script src="~/js/main.min.js"></script>
Because I think main.min.js is only generated when building for production. So if that's correct, how do you reference when dev? Do I have to include in my views all the scripts and css using the Environment Include tag? and then use Environment exclude tag for the main.min.js?
Related
It seems like you should be able to specify a fallback layout for all pages in an 11ty site using global data files and the data cascade, but I can't figure out how.
I've tried the following JSON in several locations:
{
"layout": "layouts/page.njk"
}
I've put this JSON in:
_data/default.json
_data/site.json
_data/site.11tydata.json
_data/11tydata.json
So far no luck.
This is actually something which is (as far as I'm aware) not yet possible by default in Eleventy. You can use a directory data file to specify a layout for all files nested within that directory, but that doesn't currently work from the root of the project. There was a feature request for this on GitHub.
In that same GitHub issue a workaround was suggested, which works pretty well: namely to make a layout.js file in the _data folder which exports a string pointing to the layout location.
I gave it a quick test just now with the following setup, and it seems to work as desired:
I hope that helps!
My solution is to put all of my template files in a directory called pages. In my .eleventy.js config, I set my input to pages. Ex:
module.exports = eleventyConfig => {
return {
dir: {
input: 'pages',
}
};
};
Then, following the Eleventy documentation, you can set a JSON file in pages called pages.json. That file should look like the following:
{
"layout": "default"
}
And with that, all of my pages, the index page included, default to the default layout. If you need to override a page, you can include the layout in the frontmatter. Or if you want to override everything in the directory, just include a <directory-name>.json file in that directory with the layout specified.
I haven't personally ran into any issues with this setup, and it is an added bonus to keep all of my templates together and not mixed with other config files as well.
The method given by #user13601182 worked for me.
Another option is to add a data file at the top level of your source folder. It needs to have the same name as the folder followed by 11tydata.js or 11tydata.json. For example, if your source folder is named src, the file would be src.11tydata.js or src.11tydata.json
Ex:
src/src.11tydata.js
module.exports = {
// Set a default layout for everything in the src folder and below.
layout: "layouts/default.njk"
}
From the Eleventy docs:
Try adding { "layout": "layouts/post.njk" } to posts/posts.json to configure a layout for all of the templates inside of posts/*.
Short version:
I'm updating some old libs to try to get them in AMD/requirejs format for management, but some of them have dependencies on old code.
Main Question:
I'm primarily confused as to what to list in the:
define(['what','goes','here'],function('what','needs','to','be','here'){})
and what goes in the shim dependencies list when dealing with combinations of AMD and non-AMD tools, and things like jquery-ui and jquery plugins.
ADDITIONAL INFO
The problem:
One of the older libraries depends on .draggable() from (and older version of) jquery-ui, some old version of a jquery plugin called 'onScreen', a spinner modal called spin.js -- all of which are not AMD friendly. (I also implemented an update to an AMD friendly new version of dropzone)
Two of the older libraries also use a modal library called vex which requires a dependency of vex.dialog. The existing site has an old version that is uglified.
I'm trying not to completely revamp this code as the longer term goal would be to remove those dependencies entirely, but I may not have to the time now to figure out what they are doing.
I've tried every combination of define(['list','of','stuff']) I can think of, but some of the libraries like spin (class Spinner), vex/vex.dialog and onScreen still don't always load properly. (sometimes I get one, but then lose another)
Can I define a shim AND include a list of AMD modules in the define? And if so, do I include the AMD list of dependencies in the shim in require.config? What goes where and why?
My libraries:
ImageSelector (requires AwsHelper, Utilities and ImageLayout below)
-- uses jquery (AMD), dropzone (AMD) and an old jquery plugin called jquery.onscreen.js (non-AMD)
-- depends on vex and vex.dialog (non-AMD)
-- uses .draggable() from old jquery-ui (non-AMD)
-- calls a global function 'loadSpinner' which uses spin.js (non-AMD -- see Utilities below)
ImageLayout (requires AwsHelper and Utilities - has attached instance of ImageSelector as a property .selector for methods that work in conjunction with the selector)
-- uses jquery (AMD)
-- also utilizes vex/vex.dialog (non-AMD)
Utilities
-- I'm trying to move the loadSpinner() function that requires spin.js (class Spinner, non-AMD) into this
-- I've managed thus far to avoid dependencies on things like jquery in this by refactoring code
Long version:
I'm trying to update some website code to use require.js for dependency management and to make the code more portable. But I'm running into a number of dependencies on old code that don't appear to be AMD-ready. Where possible, I'm trying to replace these with updated code and/or replace their functionality entirely, but in a number of cases, the code is minified and it's difficult to get a quick handle on what it's doing.
Rather than getting mired in minutia of trying to figure out and either replace or update these things, I read about how 'shim' can be used in some cases to handle these types of non-AMD code, but I'm still unclear on how to configure them.
Here's what I have... I have three libraries I have updated and one new one I created. One called 'ImageSelector' builds a web-gui to allow uploading files with dropzone. (My reason for updating it is that I converted it from using a local filesystem to using Amazon AWS S3 storage.) A second one called 'ImageLayout' handles the business logic of creating a product layout of photos selected by the user. (ImageSelector is split into two frames, a left one for uploading and sorting user files into folders, a right one for building the layout. Thus ImageSelector is dependent on ImageLayout)
The third library is one I created just with a number of repeatedly use 'utility' functions used across the website. There is an existing structured-code version of this in global scope with just a list of functions like roundPrecision(), sanitizeFilename(), escapeRegex(), baseName(), etc. I was going to build this with static methods, but then realized I can customize it if I spawn instances of it instead (e.g. I can change the characters 'sanitized' for different applications with global instance parameters)
The new one is the AwsHelper which is not a problem as it's entirely new code and handles all the interaction with Amazon AWS and S3. It was created in a define() AMD format while the others I have converted to define()/export format.
Anyway, some functions of the ImageLayout can be used independently by the order system, but for the most part, it's used as a dependency of the ImageSelector. AwsHelper is used mostly by ImageSelector but there are two functions in ImageLayout that utilize it. All of the above use the Utilities library.
My guess is something like this in the config (using ImageSelector as an example, but I'm wondering if "jquery" an "dropzone" need to be in there or the function define or both?)
shim: {
"ImageSelector": {
deps: ["jquery","dropzone","vex","vex.dialog","jquery-ui","jquery.onscreen"]
}
}
Additional require.js semantic questions:
(I'll post these separately if needed, but they may be short-answer and related)
Is there anything anywhere that shows how require.js searches for files? e.g. I understand about r.js for uglifying, but in some cases I can't track down the original code for these things. Can filenames include .min.js on the end or version numbers and will require.js still find them or should I rename and/or symlink files? e.g. jquery.js vs jquery-1.7.min.js for example.
The spin.js referenced above actually includes a class definition called 'Spinner'. How do I represent that in the config/shim?
Well, I posted that based on my experimenting the last 3 days riddled with failures, expecting more trouble. But apparently, shim was straightforward and having the required libs in more than one place (shim definitions and define([])) wasn't a problem.
I took a blind guess going through the examples on the require.js and came up with this configuration and amazingly it worked first try! (which makes me nervous as this is the first time I've gotten this code to work with no errors since trying to import it to require.js)
Here's what I came up with:
requirejs.config({
"baseUrl": "/js/lib",
"paths": {
"ImageSelector" : "../awsS3/ImageSelector",
"ImageLayout" : "../awsS3/ImageLayout",
"AwsHelper" : "../awsS3/AwsHelper",
"Utilities" : "../awsS3/Utilities"
},
"shim": {
"jquery.onscreen": {
"deps": ['jquery'],
"exports": 'jQuery.fn.onScreen'
},
"jquery-ui" : ['jquery'],
"vex.dialog" : ['jquery','vex'],
"vex" : ['jquery'],
"spin" : {
"exports": "Spinner"
},
"aws-sdk" : {
"exports" : "AWS"
},
"Utilities": ["spin"],
"AwsHelper": ["jquery","aws-sdk"],
"ImageSelector": {
"deps" : ["jquery","dropzone","vex","vex.dialog","jquery-ui","jquery.onscreen","ImageLayout","AwsHelper","Utilities"]
},
"ImageLayout": {
"deps" : ["jquery","vex","vex.dialog","Utilities"]
}
}
});
I also noted that some of the version naming was handled in the paths, thus I just named my libs in the paths and got rid of my "app/" directory reference altogether.
I was trying out ASP.NET Core with F# using the aspnet Yeoman template, and I found something I didn't expect in project.json:
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true,
"debugType": "portable",
"compilerName": "fsc",
"compile": {
"includeFiles": [
"Controllers.fs",
"Startup.fs",
"Program.fs"
]
}
If I move any of the existing files, I get a build error. If I change the includeFiles property to a single string with the value *.fs, I get the following message:
The 'includeFiles' property cannot contain wildcard characters.
The F# project templates from the dotnet CLI also include this structure in their project.json.
Having to add every single file to your project.json manually seems like a pretty big productivity impediment to using F# with .NET Core. Is there any way around this currently?
In F# you have to explicitly define the order in which source files are compiled.
So wildcard doesn't make sense in any F# build system.
A good blog post about Organizing modules and files
My team uses a custom NuGet package for installing jQuery UI, which puts the theme files into a directory structure like this:
Content
jquery-ui-1.10.3
images
jquery-ui.css
jquery-ui.min.css
I'm trying to use ASP.NET MVC 4 bundles to include this content in the BundleConfig class inside my application's App_Start folder like so:
bundles.Add( new StyleBundle( "~/bundles/css" )
.Include( "~/Content/normalize-{version}.css",
"~/Content/jquery-ui-{version}/jquery-ui.css",
"~/Content/Site.css" ) );
This throws an error when I run the site:
Directory does not exist.
Parameter name: directoryVirtualPath
I also tried:
bundles.Add( new StyleBundle( "~/bundles/css" )
.Include( "~/Content/normalize-{version}.css" )
.IncludeDirectory( "~/Content/jquery-ui-*", "*.css" )
.Include( "~/Content/Site.css" ) );
That doesn't work either (obviously). I can explicitly specify the version on the folder, but that defeats part of the benefit of using the bundle.
So how can I use a wildcard in the folder path?
You could use the overloaded version of IncludeDirectory which searches subdirectories.
Suppose you have the following file:
\Root\Content\jquery-ui-1.10.3\jquery-ui.css
Use this code to find and add it:
.IncludeDirectory("~/Content", "jquery-ui.css", true)
This is useful because it will always find jquery-ui.css, regardless of where you put it.
The downside to this method is that it will search for and include all jquery-ui.css files that it finds, which could cause some bugs if you don't ensure that only one jquery-ui.css exists.
(Remember that searching for subdirectories will also still search the root directory i.e. ~/Content)
Is there a way to customize the way Asp.Net MVC4 bundling&minification feature minifies the js files?
Meaning, I don't want to completely turn off minification, but "as is" it just breaks AngularJs.
Since AngularJs uses DI and IoC approach for injecting services in controllers, the following:
function MyController($scope) { }
Once minified, becomes:
function MyController(n) { }
Normally that wouldn't be a problem, but AngularJs uses the parameter names to understand which service to inject. So $scope should remain $scope, as well as any other parameter in angular controllers. Everything else, like local variables, etc, should be minified normally.
I can't find any clear documentation on how to configure Mvc4 minification, and it seems rather dumb for it to be "all or nothing" so I think I'm missing something.
Thanks.
Actually you can (and should!) write AngularJS code so it is "minification safe". Details are described in the "Dependency Annotation" section of http://docs.angularjs.org/guide/di but in short, for globally defined controllers you can write:
MyController.$inject = ['$scope'];
Please note that globally defined controllers are polluting global namespace (see this for more details) and should be avoided. If you declare a controller on a module level you can make it minification-safe as well:
angular.module('mymodule', []).controller('MyController', ['$scope', function($scope){
//controller code goes here
}]);
if you still want to control what to minify and what not (or if you want to include an already minified version by the plugin vendor) just declare two bundles, and only minify one of them on your BundleConfig.cs:
var dontMinify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxx.js");
bundles.Add(dontMinify);
var minify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/yyyyyy.js");
minify.Transforms.Add(new JsMinify());
bundles.Add(minify);
For those of you who don't want/can't be arsed to write the "minification-safe" angular-DI syntax, and don't care about variable names being obfuscated, I used BundleTransfomer along with Yui Js minifier - available via nuget:
Install-Package BundleTransformer.Core
Install-Package BundleTransformer.Yui
Gives VERY fine-grained control over minification/obfuscation. In the angular world, just set the obfuscateJavascript within the yui web.config section to false.