Sencha Touch build - exclude files - javascript

In my Sencha application I have a Config.js file containing some service URLs:
Ext.define('MyApp.utils.Config', {
singleton : true,
config : {
authBaseUrl : '...',
serviceBaseUrl : '...',
reportsBaseUrl : '...',
imagesUrl : '...'
},
constructor : function (config) {
this.initConfig(config);
}
});
Before deployment I use the
sencha app build
command from the Sencha Touch SDK to minify and concatenate files etc.
My problem is that the build process will also add config.js to the minified app.js file, although it would be very useful if I could edit it without the need of rebuilding / redeploying the whole application. I haven't found any means to change the behaviour of the build process.
So after building the application I would like to have these three js files:
sdk/sencha-touch.js (concatenated, minified, cached in localstorage after the first download)
app.js (concatenated, minified, cached in localstorage after the first download)
config.js (left untouched, without caching it in the localstorage)

Break it out from the app so that it isn't bundled, then put a reference to it in app.json, this has worked well for me in similar cases.
I also have a config.js that is repeatedly modified during my development, so in my app.json it would look like this:
"js": [
{
"path": "sdk/sencha-touch-all.js"
},
{
"path": "config.js"
},
{
"path": "app.js",
"bundle": true,
"update": "full"
}
],
This makes sure that your config.js file is included in the build.
Then you need to add the script to your app.html file, just make sure that it is loaded before your main app.js. Mine looks like this (autogenerated from Sencha Architect):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>llm</title>
<link rel="stylesheet" href="resources/css/llm.css">
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script src="sdk/sencha-touch-all.js"></script>
<script src="config.js"></script>
<script src="cordova-2.0.0.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body></body>
</html>
Hope that this helps you!

Related

where to find or how to set htmlWebpackPlugin.options.title in project created with vue cli 3?

I wanted to set title to my webpage created with vue cli 3 and thus looked into public/index.html. There, I found <title><%= htmlWebpackPlugin.options.title %></title>.
How do I set and modify htmlWebpackPlugin.options.title in vue cli 3 project?
Looking at the popularity of the question, I decided to add an elaborate answer with references to make it more authentic and complete. I have also created an article on this topic and covered this topic in this and this courses.
Though the question is looking for setting htmlWebpackPlugin.options.title, the ultimate effect is changing the title of the web-page.
1. Most convenient and trivial solution
The simplest way to do this is to modify the public/index.html and hard-code the title.
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
This is the default public/index.html that is generated by vue cli. And in this, you just need to change
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
to
<title>Title of your choice</title>
2. Change the name field in package.json
Another simple solution is to change the "name": "your-project-name". However, there are many restrictions on the name you can use in package.json. You can read more about this here. Basically, package.json must contain a name and that must be lowercase and one word, and may contain hyphens and underscores.
3. Using pages field in vue.config.js
vue.config.js is an optional file that you can add to provide additional configurations to Vue CLI and this file, if present, will be automatically loaded by Vue CLI. You need to create vue.config.js in the root folder - the folder containing you package.json file.
According to Vue documentation, you can use pages field to define entrypoint for multi-page app. However, you can also use this to define title for single page app as well. Create vue.config.js in the root directory and add pages field to your exports as follows:
module.exports = {
pages: {
index: {
// entry for the page
entry: 'src/main.js',
title: 'My Title',
},
}
}
Note that if you are already running development server, this change will be reflected only when you stop and restart the development server. In other words, these changes will not be hot reloaded.
4. Chaining Webpack
You can chain Webpack in vue.config.js as shown below
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].title = "My Vue App";
return args;
})
}
}
Note that similar to solution 3, this change will be reflected only when you stop and restart the development server, in case you are already running development server. In other words, these changes will not be hot reloaded.
5. Modify title in lifecycle hooks using JavaScript
The next solution in the list is to use JavaScript to modify the title. You can do this either in mounted lifecycle hook of your root component or if you want different title for different routes, you can do the same for components loaded by each route.
<script>
export default {
data() {
return {
//
};
},
mounted() {
document.title = 'new title'
}
}
</script>
6. Use Vue Meta
Finally you can use Vue Meta to manage all metadata for your Vue app including title. First you need to add Vue Meta to your project and then use metaInfo field as shown below to configure metadata for your page or route.
{
metaInfo: {
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ title: 'My title'}
]
}
}
Conclusion
The first 4 solutions are static ways of changing your title or in other words you can't change your title at runtime using these ways. Also all of these are not hot reloaded. The last 2 options use JavaScript and can manipulate the title at runtime.
create a file vue.config.js at the root
//vue.config.js
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].title = "My Vue App";
return args;
})
}
}
see https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-plugin
Update the name property in your package.json file
{
"name": "URL-friendly_app-name",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
...
},
"devDependencies": {
...
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
Update:
The above mentioned method will only work if you use a URL friendly title.
There are a couple of other ways to do it
From the Vuejs official documentation Pages Configuration, you can use the html plugin configuration to specify the title for different pages
Use the environement variables Modes and Environment Variables to hold your app/page title. I personally prefer and use this method.
.env (or any .env.[mode])
VUE_APP_NAME=Application flixible name
And this is how you call it in different places in your app
AnyComponent.vue (as a data property)
TypeScript
appName: string = process.env.VUE_APP_NAME
Javascript
appName: process.env.VUE_APP_NAME
anyHTML.html
<%= process.env.VUE_APP_NAME %>
Just correcting one of the scripts with the green check
<script>
export default {
data() {
return {
//
};
}
mounted() {
document.title = 'new title'
}
}
</script>
If you are using the vue-pwa plugin, the name is set within the site.webmanifest file.
I have simply assigned value fo htmlWebpackPlugin.options.title something like this.
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title="WebStore" %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script type="module" src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.js"></script>
</body>
</html>
Simple and I think the best way is to update the name inside the packer.json and you need to restart your app
package.json file:
{
"name": "my title app",
}
If you're using vue router you can do it through the router's index file. In the router.beforeEach method you just have to change the document.title to your routes title.
const DefaultPageTitle = "Default title"
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "home",
meta: {
title: "Your Title"
},
},
}
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
setPageTitle(to);
next();
});
function setPageTitle(to: RouteLocationNormalized) {
const hasMetaTitleString = typeof to.meta.title == 'string';
if (!hasMetaTitleString) {
return document.title = DefaultPageTitle;
}
return document.title = to.meta.title as string;
}

Electron together with live mode in Angular isn't loading node_module resources

Context
I'm writing an application with Electron and Angular 2+ using Angular CLI. I've set up my electron .js file to point to the URL provided by the ng serve command, that usually is localhost:4200, in order to capture the code changes. Some considerations:
The address localhost:4200 points to index.html;
index.js is my Electron entry point script
Here is my index.js file used as an entry point for the electron module.
const {app, BrowserWindow} = require('electron');
const url = require('url');
const path = require('path');
let win = null;
function createWindow() {
win = new BrowserWindow({width: 1000, height: 600, show: false});
win.loadURL('http://localhost:4200');
win.maximize();
win.on('closed', () => {
win = null;
});
win.on('ready-to-show', () => {
win.show();
});
win.webContents.openDevTools();
}
app.on('ready', () => {
createWindow();
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
And my index.html file:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>BRISA Carbon</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!--Clarity Design Elements-->
<link rel="stylesheet" href="../node_modules/clarity-icons/clarity-icons.min.css">
<script type="text/javascript" src="../node_modules/#webcomponents/custom-elements/custom-elements.min.js"></script>
<script type="text/javascript" src="../node_modules/clarity-icons/clarity-icons.min.js"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
My Problem
When I run ng serve, the node_modules resources inside the .html file are not being loaded and the Chrome console outputs the following messages
I know that the path to the resources are correct because I'm using WebStorm IDE and I can go to the referenced element through a link like this image below.
Why my resources are not being loaded when I'm running in Angular live mode?
For everyone that is having this same problem, I just found a solution. Instead of loading my resources through the index.html file, I've placed them in the .angular-cli.json. Basically, Angular 2+ has the own way of importing resources and seems that is not correct loading resources from the main .html file.
Well, for scripts (I mean, .js files), I'm placing it in the scripts array and styles inside the styles array. The .angular-cli.json file section that I've changed looks like this:
"styles": [
"styles.css",
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css"
],
"scripts": [
"../node_modules/#webcomponents/custom-elements/custom-elements.min.js",
"../node_modules/clarity-icons/clarity-icons.min.js"
]
Hope that this information will help someone else. For me everything is working just fine.
I assume you're experiencing the same problem when you're visiting localhost:4200 in your browser also?
In your index.html you're referencing to ../node_modules/ ... which works in your IDE because that's how the folder structure looks like.
Let's say your folder structure looks like this:
node_modules/
src/
And src is the folder that your server's using as root. Then the server wont be able to retrieve files from .. (since a root dir has no parent dir).
Instead of referencing to the JS files in your index.html, you should import/require them in your other JS files. Exactly how you do that depnds on your building/bundling tools (eg Webpack and/or Babel).
import '#webcomponents/custom-elements/custom-elements.min.js'
import 'clarity-icons/clarity-icons.min.js'
import 'clarity-icons/clarity-icons.min.css' // Assumes that you use webpack and webpack-css-loader, for example

How to use relative urls in angular 1.5 across all modules

I'm using angular 1.5 and webpack to generate a dist folder with my angular aplication.
This is my folder structure:
--app
--dist
--loginComponent
--login.html
--homeComponent
--home.html
...
--app.css
--app.js
--index.html
And this is my index.html:
<!doctype html>
<html lang="es" ng-app="firmaDigitalApp" ng-strict-di>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="dist/app.css">
<script src="dist/app.js"></script>
</head>
<body>
<app></app>
</body>
</html>
Everything good so far, the problem is that app.js generated is not accessing the html by its path in a relative manner so it can't find the resource (instead of looking for home.html in context/dist/homeComponent.html, it's looking for it in context/homeComponent.html).
Just in case, this is homeModule.js:
require('./administradorComponent/administradorModule.js');
require('./definicionComponent/definicionModule.js');
var controller = require('./homeController');
var homeModule = angular.module('homeModule', [ 'administradorModule', 'definicionModule' ]);
homeModule.component('homeComponent',
{
templateUrl : 'homeComponent/home.html',
$routeConfig : [
{
path : '/administrador/...',
name : 'Administrador',
component : 'administradorComponent',
useAsDefault : true
}]
});
homeModule.controller('homeController', [ '$rootScope', '$location', '$log', controller ]);
What can I do so my angular application resources use relative paths to access each other so I don't have to type dist/ over and over again?
Let me know if you need more information.
Rather than using templateUrl, I'd recommend using html-loader to make your templates be built into your output file (i.e. app.js). If you set that up, you can just do:
template: require("homeComponent/home.html") // Resolves to a string
This will cause your bundle to take a little longer to download up front, as all the templates will get loaded too, but you won't have to wait for the templates to load asynchronously when the component is initialized, so it evens out in my opinion.

Have Grunt generate index.html for different setups

I'm trying to use Grunt as a build tool for my webapp.
I want to have at least two setups:
I. Development setup - load scripts from separate files, without concatenation,
so my index.html would look something like:
<!DOCTYPE html>
<html>
<head>
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
</head>
<body></body>
</html>
II. Production setup - load my scripts minified & concatenated in one file,
with index.html accordingly:
<!DOCTYPE html>
<html>
<head>
<script src="js/MyApp-all.min.js" />
</head>
<body></body>
</html>
The question is, how can I make grunt make these index.html's depending on the configuration when I run grunt dev or grunt prod?
Or maybe I'm digging in the wrong direction and it would be easier to always generate MyApp-all.min.js but put inside it either all my scripts (concatenated) or a loader script that asynchronously loads those scripts from separate files?
How do you do it, guys?
I recently discovered these Grunt v0.4.0 compatible tasks:
grunt-preprocess
Grunt task around preprocess npm module.
grunt-env
Grunt task to automate environment configuration for future tasks.
Below are snippets from my Gruntfile.js.
ENV setup:
env : {
options : {
/* Shared Options Hash */
//globalOption : 'foo'
},
dev: {
NODE_ENV : 'DEVELOPMENT'
},
prod : {
NODE_ENV : 'PRODUCTION'
}
},
Preprocess:
preprocess : {
dev : {
src : './src/tmpl/index.html',
dest : './dev/index.html'
},
prod : {
src : './src/tmpl/index.html',
dest : '../<%= pkg.version %>/<%= now %>/<%= ver %>/index.html',
options : {
context : {
name : '<%= pkg.name %>',
version : '<%= pkg.version %>',
now : '<%= now %>',
ver : '<%= ver %>'
}
}
}
}
Tasks:
grunt.registerTask('default', ['jshint']);
grunt.registerTask('dev', ['jshint', 'env:dev', 'clean:dev', 'preprocess:dev']);
grunt.registerTask('prod', ['jshint', 'env:prod', 'clean:prod', 'uglify:prod', 'cssmin:prod', 'copy:prod', 'preprocess:prod']);
And in the /src/tmpl/index.html template file (for example):
<!-- #if NODE_ENV == 'DEVELOPMENT' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="../src/js/foo1.js"></script>
<script src="../src/js/foo2.js"></script>
<script src="../src/js/jquery.blah.js"></script>
<script src="../src/js/jquery.billy.js"></script>
<script src="../src/js/jquery.jenkins.js"></script>
<!-- #endif -->
<!-- #if NODE_ENV == 'PRODUCTION' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdn.foo.com/<!-- #echo name -->/<!-- #echo version -->/<!-- #echo now -->/<!-- #echo ver -->/js/<!-- #echo name -->.min.js"></script>
<!-- #endif -->
I'm sure my setup is different than most people, and the usefulness of the above will depend on your situation. For me, while it's an awesome bit of code, the Yeoman grunt-usemin is a more robust than I personally need.
NOTE: I just discovered the above listed tasks today, so I might be missing a feature and/or my process may change down the road. For now, I'm loving the simplicity and features that grunt-preprocess and grunt-env have to offer. :)
I'm not sure if it will be of any help to anyone, but I've created this demo repository on GitHub that shows a complete (and more complex setup) using the technique(s) I've outlined above.
I've come up with my own solution. Not polished yet but I think I'm going to move in that direction.
In essense, I'm using grunt.template.process() to generate my index.html from a template that analyzes current configuration and produces either a list of my original source files or links to a single file with minified code. The below example is for js files but the same approach can be extended to css and any other possible text files.
grunt.js:
/*global module:false*/
module.exports = function(grunt) {
var // js files
jsFiles = [
'src/module1.js',
'src/module2.js',
'src/module3.js',
'src/awesome.js'
];
// Import custom tasks (see index task below)
grunt.loadTasks( "build/tasks" );
// Project configuration.
grunt.initConfig({
pkg: '<json:package.json>',
meta: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
jsFiles: jsFiles,
// file name for concatenated js
concatJsFile: '<%= pkg.name %>-all.js',
// file name for concatenated & minified js
concatJsMinFile: '<%= pkg.name %>-all.min.js',
concat: {
dist: {
src: ['<banner:meta.banner>'].concat(jsFiles),
dest: 'dist/<%= concatJsFile %>'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
dest: 'dist/<%= concatJsMinFile %>'
}
},
lint: {
files: ['grunt.js'].concat(jsFiles)
},
// options for index.html builder task
index: {
src: 'index.tmpl', // source template file
dest: 'index.html' // destination file (usually index.html)
}
});
// Development setup
grunt.registerTask('dev', 'Development build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', true);
grunt.config('isConcat', false);
grunt.config('isMin', false);
// run tasks
grunt.task.run('lint index');
});
// Production setup
grunt.registerTask('prod', 'Production build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', false);
grunt.config('isConcat', true);
grunt.config('isMin', true);
// run tasks
grunt.task.run('lint concat min index');
});
// Default task
grunt.registerTask('default', 'dev');
};
index.js (the index task):
module.exports = function( grunt ) {
grunt.registerTask( "index", "Generate index.html depending on configuration", function() {
var conf = grunt.config('index'),
tmpl = grunt.file.read(conf.src);
grunt.file.write(conf.dest, grunt.template.process(tmpl));
grunt.log.writeln('Generated \'' + conf.dest + '\' from \'' + conf.src + '\'');
});
}
Finally, index.tmpl, with generation logic baked in:
<doctype html>
<head>
<%
var jsFiles = grunt.config('jsFiles'),
isConcat = grunt.config('isConcat');
if(isConcat) {
print('<script type="text/javascript" src="' + grunt.config('concat.dist.dest') + '"></script>\n');
} else {
for(var i = 0, len = jsFiles.length; i < len; i++) {
print('<script type="text/javascript" src="' + jsFiles[i] + '"></script>\n');
}
}
%>
</head>
<html>
</html>
UPD. Found out that Yeoman, which is based on grunt, has a built-in usemin task that integrates with Yeoman's build system. It generates a production version of index.html from information in development version of index.html as well as other environment settings. A bit sophisticated but interesting to look at.
I dislike the solutions here (including the one I previously gave) and here's why:
The problem with the highest voted answer is that you have to manually sync the list of script tags when you add/rename/delete a JS file.
The problem with the accepted answer is that your list of JS files can't have pattern matching. This means you've got to update it by hand in the Gruntfile.
I've figured out how to solve both of these issues. I've set up my grunt task so that every time a file is added or deleted, the script tags automatically get generated to reflect that. This way, you don't need to modify your html file or your grunt file when you add/remove/rename your JS files.
To summarize how that works, I have a html template with a variable for the script tags. I use https://github.com/alanshaw/grunt-include-replace to populate that variable. In dev mode, that variable comes from a globbing pattern of all my JS files. The watch task recalculates this value when a JS file is added or removed.
Now, to get different results in dev or prod mode, you simply populate that variable with a different value. Here's some code:
var jsSrcFileArray = [
'src/main/scripts/app/js/Constants.js',
'src/main/scripts/app/js/Random.js',
'src/main/scripts/app/js/Vector.js',
'src/main/scripts/app/js/scripts.js',
'src/main/scripts/app/js/StatsData.js',
'src/main/scripts/app/js/Dialog.js',
'src/main/scripts/app/**/*.js',
'!src/main/scripts/app/js/AuditingReport.js'
];
var jsScriptTags = function (srcPattern, destPath) {
if (srcPattern === undefined) {
throw new Error("srcPattern undefined");
}
if (destPath === undefined) {
throw new Error("destPath undefined");
}
return grunt.util._.reduce(
grunt.file.expandMapping(srcPattern, destPath, {
filter: 'isFile',
flatten: true,
expand: true,
cwd: '.'
}),
function (sum, file) {
return sum + '\n<script src="' + file.dest + '" type="text/javascript"></script>';
},
''
);
};
...
grunt.initConfig({
includereplace: {
dev: {
options: {
globals: {
scriptsTags: '<%= jsScriptTags(jsSrcFileArray, "../../main/scripts/app/js")%>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generated/',
flatten: true,
cwd: '.',
expand: true
},
prod: {
options: {
globals: {
scriptsTags: '<script src="app.min.js" type="text/javascript"></script>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generatedprod/',
flatten: true,
cwd: '.',
expand: true
}
...
jsScriptTags: jsScriptTags
jsSrcFileArray is your typical grunt file-globbing pattern. jsScriptTags takes the jsSrcFileArray and concatenates them together with script tags on both sides. destPath is the prefix I want on each file.
And here's what the HTML looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Example</title>
</head>
<body>
##scriptsTags
</body>
</html>
Now, as you can see in the config, I generate the value of that variable as a hard coded script tag when it's run in prod mode. In dev mode, this variable will expand to a value like this:
<script src="../../main/scripts/app/js/Constants.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Random.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Vector.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/StatsData.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Dialog.js" type="text/javascript"></script>
Let me know if you have any questions.
PS: This is a crazy amount of code for something I'd want to do in every client-side JS app. I hope someone can turn this into a reusable plugin. Maybe I will some day.
I have been asking myself the same question for a while, and I think this grunt plugin could be configured to do what you want: https://npmjs.org/package/grunt-targethtml. It implements conditional html tags, that depend on the grunt target.
I was looking for a more simple, straight forward solution so I combined the answer from this question:
How to place if else block in gruntfile.js
and came up with following simple steps:
Keep two versions of your index files as you listed and name them index-development.html and index-prodoction.html.
Use the following logic in your Gruntfile.js's concat/copy block for your index.html file:
concat: {
index: {
src : [ (function() {
if (grunt.option('Release')) {
return 'views/index-production.html';
} else {
return 'views/index-development.html';
}
}()) ],
dest: '<%= distdir %>/index.html',
...
},
...
},
run 'grunt --Release' to choose the index-production.html file and leave off the flag to have the development version.
No new plugins to add or configure and no new grunt tasks.
This grunt task named scriptlinker looks like an easy way to add the scripts in dev mode. You could probably run a concat task first and then point it to your concatenated file in prod mode.
grunt-dom-munger reads and manipulates HTML with CSS selectors. Ex. read tags from your html. Remove nodes, add nodes, and more.
You can use grunt-dom-munger to read all your JS files that are linked by your index.html, uglify them and then use grunt-dom-munger again to modify your index.html to only link the minified JS
I found a grunt plugin called grunt-dev-prod-switch. All it does is comment out certain blocks it looks for based on an --env option you pass to grunt (although it limits you to dev, prod, and test).
Once you set it up as it explains here, you can run for example:
grunt serve --env=dev, and all it does is comment out the blocks which are wrapped by
<!-- env:test/prod -->
your code here
<!-- env:test/prod:end -->
and it will uncomment out blocks which are wrapped by
<!-- env:dev -->
your code here
<!-- env:dev:end -->
It also works on javascript, I use it for setting up the right IP address to connect to for my backend API. The blocks just change to
/* env:dev */
your code here
/* env:dev:end */
In your case, it would be as simple as this:
<!DOCTYPE html>
<html>
<head>
<!-- env:dev -->
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
<!-- env:dev:end -->
<!-- env:prod -->
<script src="js/MyApp-all.min.js" />
...
<!-- env:prod:end -->
</head>
<body></body>
</html>
grunt-bake is a fantastic grunt script that would work great here. I use it in my JQM auto build script.
https://github.com/imaginethepoet/autojqmphonegap
Take a look at my grunt.coffee file:
bake:
resources:
files: "index.html":"resources/custom/components/base.html"
This looks at all the files in base.html and sucks them in to create index.html works fantastic for multipage apps (phonegap). This allows for easier development as all devs are not working on one long single page app (preventing lots of conflict checkins). Instead you can break up the pages and work on smaller chunks of code and compile to the full page using a watch command.
Bake reads the template from base.html and injects the component html pages on watch.
<!DOCTYPE html>
jQuery Mobile Demos
app.initialize();
<body>
<!--(bake /resources/custom/components/page1.html)-->
<!--(bake /resources/custom/components/page2.html)-->
<!--(bake /resources/custom/components/page3.html)-->
</body>
You can take this a step further and add injections in your pages for "menus" "popups" etc so you can really break pages into smaller manageable components.
Use a combination of wiredep https://github.com/taptapship/wiredep and usemin https://github.com/yeoman/grunt-usemin in order to have grunt take care of these tasks. Wiredep will add your dependencies one script file at a time, and usemin will concatenate them all into a single file for production. This can then be accomplished with just some html comments. For instance, my bower packages are automatically included and added to the html when I run bower install && grunt bowerInstall:
<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
This answer is not for noobs!
Use Jade templating ... passing variables to a Jade template is a bog standard use case
I am using grunt (grunt-contrib-jade) but you don't have to use grunt. Just use the standard npm jade module.
If using grunt then your gruntfile would like something like ...
jade: {
options: {
// TODO - Define options here
},
dev: {
options: {
data: {
pageTitle: '<%= grunt.file.name %>',
homePage: '/app',
liveReloadServer: liveReloadServer,
cssGruntClassesForHtmlHead: 'grunt-' + '<%= grunt.task.current.target %>'
},
pretty: true
},
files: [
{
expand: true,
cwd: "src/app",
src: ["index.jade", "404.jade"],
dest: "lib/app",
ext: ".html"
},
{
expand: true,
flatten: true,
cwd: "src/app",
src: ["directives/partials/*.jade"],
dest: "lib/app/directives/partials",
ext: ".html"
}
]
}
},
We can now easily access the data passed by grunt in the Jade template.
Much like the approach used by Modernizr, I set a CSS class on the HTML tag according to the value of the variable passed and can use JavaScript logic from there based on whether the CSS class is present or not.
This is great if using Angular since you can do ng-if's to include elements in the page based on whether the class is present.
For example, I might include a script if the class is present ...
(For example, I might include the live reload script in dev but not in production)
<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script>
Consider processhtml. It allows definition of multiple "targets" for builds. Comments are used to conditionally include or exclude material from the HTML:
<!-- build:js:production js/app.js -->
...
<!-- /build -->
becomes
<script src="js/app.js"></script>
It even purports to do nifty stuff like this (see the README):
<!-- build:[class]:dist production -->
<html class="debug_mode">
<!-- /build -->
<!-- class is changed to 'production' only when the 'dist' build is executed -->
<html class="production">

Check Backbone/requireJs project with Jasmine

I have a project loaded using RequireJS and I would like to test the models.
I have the following test :
require(['../../js/models/lead_sharing'], function(Lead_sharing_Model) {
describe('when instantiated', function () {
it('should exhibit attributes', function() {
var test = new Lead_sharing_Model({
attribute : 3
});
expect(test.get('attribute')).toEqual(3);
});
});
});
But I have a error " failed with error: SyntaxError: Unexpected token"...
In reality , I don't know if it's possible to test a backbone/requireJs project with Jasmine. Indeed, how can I include my views/Models... without require config (like definition of the paths...)
Thanks you
Ps : just a small edit to specify that I would like test with a a js cmd. no in a browser. :)
It is certainly possible to test a backbone/requirejs project with jasmine. Pull the same require config used by the app into the html page that drives the unit tests. For example:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="vendor/jasmine.css">
</head>
<body>
<script src="vendor/jasmine.js"></script>
<script src="vendor/jasmine-html.js"></script>
<script src="../assets/js/libs/jquery.js"></script>
<script src="../assets/js/libs/underscore.js"></script>
<script src="../assets/js/libs/backbone.js"></script>
<!-- This points to the require config that is also used by the main app. -->
<script data-main="../app/config" src="../assets/js/libs/require.js"></script>
<script>
require({ paths: { spec: "../test/spec" } }, [
// Pull in all your modules containing unit tests here.
"spec/lead-sharing-specs"
], function() {
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
});
</script>
</body>
</html>
Since you want to run this outside of the browser, check out PhantomJS, grunt, and grunt-jasmine-task.

Categories