google closureCompiler doesn't want to read my goog.getMsg() - gruntjs

I'm trying to compile my js files using closure compiler, but it's giving me this error:
ERROR - goog.getMsg() function could be used only with MSG_* property or variable
my closureCompiler options are:
closureCompiler: {
options: {
compilerFile: 'temp/compiler.jar',
compilerOpts: {
compilation_level: 'ADVANCED_OPTIMIZATIONS',
//compilation_level: 'WHITESPACE_ONLY',
language_in: 'ECMASCRIPT6',
language_out: 'ECMASCRIPT5_STRICT',
formatting: 'PRETTY_PRINT',
externs: ['src/js/compiled/react-extern.js'],
warning_level: 'verbose',
summary_detail_level: 3,
output_wrapper: '"(function(){%output%}).call(window);"',
create_source_map: 'src/js/compiled/output.js.map',
manage_closure_dependencies: true,
use_types_for_optimization: null,
debug: true
},
execOpts: {
maxBuffer: 999999 * 1024
}
},
compile: {
//src: 'src/js/debug/**/*.js',
src: [
'temp/closure-library/closure/goog/base.js',
'src/js/compiled/test.js'
],
dest: 'src/js/compiled/compiled.js'
},
},
I believe I'm missing a flag, but I don't which one to write ?

You can't include goog.getMsg() in your code.
It has to be:
var MSG_SOMETHING = goog.getMsg('something');
and use the MSG_SOMETHING instead.
Google Closure Compiler enforced that, so you could write all your variable in one file and send this one to get translated.

Related

Grunt-string-replace using an object of key-value pairs

I started using grunt in my build process. In package.json I include variables to be replaced this way:
{
"name": "myApp",
"variableToReplace":{
"var1":"var1_replacement",
"var2":"var2_replacement"
},
...
}
However, I do not know how to use this variableToReplace in Gruntfile.js so that it will automatically look up all properties then replace them with the corresponding values. Is it possible using Grunt?
'string-replace': {
dist: {
files: {
//A list of files
},
options: {
//What to put here?
}
}
}
Revised Answer (after comment)
... Is there anyway to loop through the key-value pair of variableToReplace and replace, for example, var1 with var1_replacement.
Yes, this can be achieved by utilizing a Custom Task. The custom task should perform the following:
Read the variableToReplace object from package.json.
Dynamically build the options.replacements array.
Configure/set the option.replacements array using grunt.config.set
Then finally run the task using grunt.task.run.
The following Gruntfile.js demonstrates this solution:
Gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-string-replace');
grunt.initConfig({
'string-replace': {
dist: {
files: [{
expand: true,
cwd: 'src/',
src: '**/*.css',
dest: 'dist/'
}],
options: {
replacements: [] // <-- Intentionally empty and will be dynamically
// configured via `configAndRunStringReplace`.
}
}
}
});
/**
* Helper task to dynamically configure the Array of Objects for the
* `options.replacements` property in the `dist` target of the `string-replace`
* task. Each property name of the `variableToReplace` Object (found in
* `package.json`) is set as the search string, and it's respective value
* is set as the replacement value.
*/
grunt.registerTask('configAndRunStringReplace', function () {
// 1. Read the `variableToReplace` object from `package.json`.
var replacements = grunt.file.readJSON('package.json').variableToReplace,
config = [];
// 2. Dynamically build the `options.replacements` array.
for (key in replacements) {
config.push({
pattern: new RegExp(key, 'g'),
replacement: replacements[key]
});
}
// 3. Configure the option.replacements values.
grunt.config.set('string-replace.dist.options.replacements', config);
// 4. Run the task.
grunt.task.run('string-replace:dist');
});
// Note: In the `default` Task we add the `configAndRunStringReplace`
// task to the taskList array instead of `string-replace`.
grunt.registerTask('default', ['configAndRunStringReplace']);
}
Important note regarding Regular Expressions:
The docs for grunt-string-replace states:
If the pattern is a string, only the first occurrence will be replaced...
To ensure that multiple instances of the search/find string are matched and replaced the configAndRunStringReplace custom task utilizes a Regular Expression with the global g flag.
So, any instances of the following regex special characters:
\ ^ $ * + ? . ( ) | { } [ ]
which may be used in a search word (i.e. as a key/property name in your package.json) will need to be escaped. The typical way to escape these characters in a Regex is to add a backslash \ before the character (E.g. \? or \+ etc..). However, because you're using key/property names in JSON to define your search word. You'll need to double escape any of the previously mentioned characters to ensure your JSON remains valid. For Example:
Lets say you wanted to replace question marks (?) with exclamation marks (!). Instead of defining those rules in package.json like this:
...
"variableToReplace":{
"?": "!"
},
...
Or like this:
...
"variableToReplace":{
"\?": "!"
},
...
You'll need to do this (i.e. use double escapes \\):
...
"variableToReplace":{
"\\?": "!"
},
...
Original Answer
The following contrived example shows how this can be achieved:
Gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-string-replace');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), // 1. Read the package.json file.
'string-replace': {
dist: {
files: {
'dist/': ['src/css/**/*.css'],
},
options: {
replacements: [{
// 2. Use grunt templates to reference the properties in package.json
pattern: '<%= pkg.variableToReplace.var1 %>',
replacement: '<%= pkg.variableToReplace.var2 %>',
}]
}
}
}
});
grunt.registerTask('default', ['string-replace']);
}
Notes
Add pkg: grunt.file.readJSON('package.json') to the grunt.initConfig() section of your Gruntfile.js. This will parse the JSON data stored in package.json.
Use grunt templates to access the properties of package.json. The standard JavaScript dot notation is used to access the property values, (e.g. pkg.variableToReplace.var1), and is wrapped in a leading <%= and trailing %>
Using the contrived Gruntfile.js configuration above with your the package.json data (as described in your question). The following would occur:
Any instances of the string var1_replacement found in any of the .css files stored in the src/css/ directory will be replaced with the string var2_replacement.
The resultant files will be saved to the dist/ directory.

How to create source maps dynamically with grunt-closurecompiler

I can't get it to work. name_of_current_file needs to somehow be replaced with name of the current file being processed. It seems to me like the options property is only evaluated once and reused for each file.
closurecompiler: {
dev: {
files:[{
expand: true,
flatten: true,
cwd: 'www',
src: ['src/js/*.js', '!src/js/*.min.js'],
dest: 'www/build/js/',
ext: '.min.js',
}],
options: {
// Any options supported by Closure Compiler, for example:
"compilation_level": "ADVANCED_OPTIMIZATIONS",
"create_source_map": name_of_current_file+'.map',
// Plus a simultaneous processes limit
"max_processes": 4,
}
},
}
You can use the replacement variable %outname% in your source map naming.
"create_source_map": '%outname%.map'
Also, make sure you are using the officially supported Grunt Plugin.

grunt-contrib-jade compiling to single JS with cwd

I am trying to compile multiple jade templates into single JS file using grunt-contrib-jade. Problem I'm facing is that with full path to templates, I get function names with full path. I want to avoid that, so I tried using cwd (without expand). This ended up with the following:
>> Source file "test.jade" not found.
>> Source file "test2.jade" not found.
Is there any way I could achieve what I plan? My grunt config for that task is as following:
jade: {
js: {
options: {
client: true,
amd: true
},
files: [ {
cwd: 'js/views/',
src: ['*.jade'],
dest: 'js/tmp/templates.js'
} ]
}
},
Thanks in advice,
Dracco
Silly me, didn't fully read the documentation of the plugin :(.
The solution is trivial, using the processName option:
options: {
client: true,
amd: true,
processName: function(path) {
var pathChunks = path.split('.')[0].split('/');
return pathChunks[pathChunks.length - 1];
}
}

How to get grunt.file.readJSON() to wait until file is generated by another task

I'm working on setting up series of grunt tasks that work with RequireJS r.js compiler:
1) generates a .json file listing of all files in a directory
2) strips the ".js" from the filename (requirejs requires this)
3) use grunt.file.readJSON() to parse that file and use as a configuration option in my requirejs compilation task.
Here is the relevant code from my gruntfile.js:
module.exports = function (grunt) {
grunt.initConfig({
// create automatic list of all js code modules for requirejs to build
fileslist: {
modules: {
dest: 'content/js/auto-modules.json',
includes: ['**/*.js', '!app.js', '!libs/*'],
base: 'content/js',
itemTemplate: '\t{' +
'\n\t\t"name": "<%= File %>",' +
'\n\t\t"exclude": ["main"]' +
'\n\t}',
itemSeparator: ',\n',
listTemplate: '[' +
'\n\t<%= items %>\n' +
'\n]'
}
},
// remove .js from filenames in module list
replace: {
nodotjs: {
src: ['content/js/auto-modules.json'],
overwrite: true,
replacements: [
{ from: ".js", to: "" }
]
}
},
// do the requirejs bundling & minification
requirejs: {
compile: {
options: {
appDir: 'content/js',
baseUrl: '.',
mainConfigFile: 'content/js/app.js',
dir: 'content/js-build',
modules: grunt.file.readJSON('content/js/auto-modules.json'),
paths: {
jquery: "empty:",
modernizr: "empty:"
},
generateSourceMaps: true,
optimize: "uglify2",
preserveLicenseComments: false,
//findNestedDependencies: true,
wrapShim: true
}
}
}
});
grunt.loadNpmTasks('grunt-fileslist');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['fileslist','replace', 'requirejs']);
I'm running into a problem where, if the "content/js/auto-modules.json" file doesn't already exist on load of my config file, the file.readJSON() is executed immediately, before the file exists and the entire task fails and throws "Error: Unable to read file " If the file already exists, everything works beautifully.
How can I set this up so that the task configuration waits for that file to be created in the first task, and modified in the second task before it tries to load & parse the JSON in it for the third task? Or is there another way (perhaps using a different plugin) to generate a json object in one task, and then pass that object to another task?
Old post but I had a similar experience.
I was trying to load a some json config like:
conf: grunt.file.readJSON('conf.json'),
but if this file did not exist then it would fall in a heap and not do anything.
So I did the following to load it and populate defaults if it didnt exist:
grunt.registerTask('checkConf', 'ensure conf.json is present', function(){
var conf = {};
try{
conf = grunt.file.readJSON('./conf.json');
} catch (e){
conf.foo = "";
conf.bar = "";
grunt.file.write("./conf.json", JSON.stringify(conf) );
}
grunt.config.set('conf', conf);
});
You still may have some timing issues but this approach may help someone with a readJSON error.

Load an external file in a grunt-contrib-jade task

So I've got this grunt-contrib-jade setup that is working just fine
Everything is fine when I include my data in the (exported) Gruntfile myself:
module.exports = {
website: {
options: {
data: {
pageTitle: "This is my website",
greeting: "Hello world",
},
debug: true,
pretty: true
},
files: {
'build/website/index.html': 'src/jade/template/index.jade'
}
}
};
It merges my index.jade with my data values and my index.html output is the way it should be. But when I want to load an external file to define my data it goes wrong:
options: {
data: function (dest, src) {
// Return an object of data to pass to templates
return require('src/jade/template/locals.json');
},
debug: true,
pretty: true
},
files: {
'build/website/index.html': 'src/jade/template/index.jade'
}
The require path is valid, I triple checked it. It's located in the same folder as my index.jade. However I still keep getting this error:
Running "jade:website" (jade) task
>> Jade failed to compile "src/jade/template/index.jade".
>> Error: Cannot find module './locals.json'
>> Destination not written because compiled files were empty.
I tried just about everything, but I just don't see it.
Local modules need to be prepended with './' when you require them.
data: function (dest, src) {
// Return an object of data to pass to templates
return require('./src/jade/template/locals.json');
}
will work. You're not doing anything with the function (at least yet), so this could also be
data: require('./src/jade/template/locals.json')
or even
data: grunt.file.readJSON('./src/jade/template/locals.json').

Resources