How to use webpack/babel to preparse JS template strings? - javascript

Let's say for example, I want to create a rot13 template tag. You could use it like this:
let secret = rot13`This is a secret.`;
Now I could implement this tag in JavaScript, but I want to pre-parse it such that my compiled bundle would actually contain:
let secret = "Guvf vf n frperg.";
How can I do this? Do I have to create a Babel plugin to hook into their parser? What would that look like?
Now what if I want Webpack to also spit out a file called rotated_strings.txt which contains a list of all these strings that have been transformed? How do I collect them up? i.e., how do I get Babel and Webpack to communicate such that Babel can do the inline transform but somehow notify Webpack to generate this extra file?

Try out the following.
https://astexplorer.net/#/gist/89a6bdce0165d2661385828d9d85a7e0/4d745f3e8b5bfd25ba919cff567f27055d9e3a75
I have built up on what Joe Clay had created in the comments.
Right now this console logs all the things it has changed once at the end
And in the comments I have written what you can replace it with once you move it to using in your project build env (assuming it to be Node)
PS: I have used the sync APIs in comments to quickly demonstrate it, you should probably switch over to Async APIs
Update: When you write this in Babel plugin, be sure to not set quasi and cooked attrs, but use path.replaceWith(t.stringLiteral(cooked)) instead

Related

How to generate JavaScript from a template with terminal similar to Laravel's Artisan?

I have been recently been working with Laravel, and Artisan has several useful make commands that generates php from template stubs on the fly based off a class name, as well as allowing for custom make commands to speed things up.
Short of copy-pasting, there an easy tool that lets me generate plain JS in a similar way based on a templates that allows me to specify some variables to be replaced, then generated in my project?
The ultimate goal of mine for this project is to run a single terminal command with some arguments that generate all the files I need (at least 8-10 PHP files, as well as around 4 JS files), all put into the right directories that lets me do minimal "plugging in" so I can start using them right away. I can chain custom artisan commands, but the next step is getting some kind of terminal JS generator. The nature of the project is that there is approx. 12-14 files that need to be generated and generically filled in before being able to interface with a database table and the front end, so you can understand why I want to do this.
You can do it with bash like this
#!/bin/bash
file_location=path/to/dir/$1.js
if [ -e $1 ]; then
echo "File $1.js already exists!"
else
cat > $file_location <<EOF
let hi = '$2'
console.log(hi)
EOF
fi
$1 is the filename and $2 is another parameter you can pass to the script to be written in the js file.
I would look at hygen. I don't know what your output files are supposed to look like, but hygen allows you to create your own templates and generators. This has a relevant code snippet that displays some JS code. I can't give any advice beyond that as I've not used it thus far.
If this is looking like a bit too much, you can always use VS Code's templates to build up a base, but you won't have any params. A VS Code extension could overcome that I'd guess, but then you're not within a cli.

Angular 5 internationalization workflow

my current process is as follows:
Current process
I add the i18n attributes to the template.
Then I execute ng xi18n. This creates the messages.xlf file.
As soon as the process is finished, you have to copy messages.xlf and change the file extension to *.fr.xlf. In the renamed file you now manually search for all <source> tags and add the <target> tags with the translation.
If there are many different languages, this process is very time-consuming.
Problem
The problems here are the missing versioning of the translations and especially the manual adding of the <target> tags to the corresponding <source> tags.
Desired workflow
It would be desirable to have a workflow where versioning is possible and above all, the desired translation files are created automatically.
Would webpack be the right approach to solve this problem?
I just abandoned built in translation and prefered ngx-translate module.
With it you can :
- auto-extract translation string from source code
- build one app that contains all locales
- change locale during run time
If you're in an IDE that supports regex searches, then you can use regexes for search and replace such as
search: (\s*)<source>([^<]*)</source>
replace: $1\n$2<target>$3</target>
This will add a target after every source.
And about updating the translations, you are supposed to have a versioning tool, that will highlight the changes in the file. All you have to do is keep it updated at every commit you do that involves this file.
I agree that this isn't practical, and so is the fact that you can't translate typescript code. But those are workarounds that you can use in the meantime to ease your life.

Gulp task to translate JS

I'm working on a JavaScript app and have so far entered all my strings as plain text.
This is starting to feel really hacky (I'm used to gettext) so I'd prefer to wrap them all in something like {{translatable_string}} and have a gulp task just search/replace them all during the build step.
So, my question is; is there a generic (no framework-specific like angular-gettext or something like that) gettext replacer out there?
Obviously it doesn't even have to be connected to JavaScript in any way, you should be able to run it on any file type and have {{translatable_string}}:s be translated.
You may want to look into using gulp-replace. As they explained in this answer, you should be able to use it to find and replace any string that you want in the stream.
I suggest a database of strings for your translations if dynamic generation of page content is possible for your app. Starting with English or whichever is normal but the need to localize content is a tough issue without a robust system. A simple MongoDB table can be used to store the content, and when the app needs an interface it can be loaded with the right localized strings. As a for instance:
if(err) alert("Please turn off caps lock");
could become:
if(err) alert(Please_turn_off_caps_lock.English);
If you are needing to build static pages with gulp, a database in conjunction with gulp-replace sounds interesting. Using gulp-data to call up and package the strings, you can then feed it to gulp-replace and alter the files. The extensible nature of databases or document stores enable you to expand your localization without hacking on individual files or trees all the time.
Try gulp-gettext-parser.
var gettext = require("gulp-gettext-parser");
var rename = require("gulp-rename");
gulp.task("gettext", function() {
return gulp.src("src/**/*.js")
.pipe(gettext())
.pipe(rename("bundle.po"))
.pipe(gulp.dest("dist/"));
});
Perhaps what you need is mustache.js, take a look: https://github.com/janl/mustache.js/
I'm not used to work with mustache, but I had to do some updates in a project done with it, and I was surprised the capabilities it have.
If you're familiar with jade (now renamed to pug), you'll find is something similar but at the end, you're not forced to generate only html files, you cand generate any kind of text file.
This blog could be helpful to understand the differences between some other templating languages over Nodejs: https://strongloop.com/strongblog/compare-javascript-templates-jade-mustache-dust/

Understanding the Communication between Modules in jQuery Source Code Structure [duplicate]

Uncompressed jQuery file: http://code.jquery.com/jquery-2.0.3.js
jQuery Source code: https://github.com/jquery/jquery/blob/master/src/core.js
What are they doing to make it seem like the final output is not using Require.js under the hood? Require.js examples tells you to insert the entire library into your code to make it work standalone as a single file.
Almond.js, a smaller version of Require.js also tell you to insert itself into your code to have a standalone javascript file.
When minified, I don't care for extra bloat, it's only a few extra killobytes (for almond.js), but unminified is barely readable. I have to scroll all the way down, past almond.js code to see my application logic.
Question
How can I make my code to be similar to jQuery, in which the final output does not look like a Frankenweenie?
Short answer:
You have to create your own custom build procedure.
Long answer
jQuery's build procedure works only because jQuery defines its modules according to a pattern that allows a convert function to transform the source into a distributed file that does not use define. If anyone wants to replicate what jQuery does, there's no shortcut: 1) the modules have to be designed according to a pattern which will allow stripping out the define calls, and 2) you have to have a custom conversion function. That's what jQuery does. The entire logic that combines the jQuery modules into one file is in build/tasks/build.js.
This file defines a custom configuration that it passes to r.js. The important option are:
out which is set to "dist/jquery.js". This is the single
file produced by the optimization.
wrap.startFile which is set to "src/intro.js". This file
will be prepended to dist/jquery.js.
wrap.endFile which is set to "src/outro.js". This file will
be appended to dist/jquery.js.
onBuildWrite which is set to convert. This is a custom function.
The convert function is called every time r.js wants to output a module into the final output file. The output of that function is what r.js writes to the final file. It does the following:
If a module is from the var/ directory, the module will be
transformed as follows. Let's take the case of
src/var/toString.js:
define([
"./class2type"
], function( class2type ) {
return class2type.toString;
});
It will become:
var toString = class2type.toString;
Otherwise, the define(...) call is replace with the contents of the callback passed to define, the final return statement is stripped and any assignments to exports are stripped.
I've omitted details that do not specifically pertain to your question.
You can use a tool called AMDClean by gfranko https://www.npmjs.org/package/amdclean
It's much simpler than what jQuery is doing and you can set it up quickly.
All you need to do is to create a very abstract module (the one that you want to expose to global scope) and include all your sub modules in it.
Another alternative that I've recently been using is browserify. You can export/import your modules the NodeJS way and use them in any browser. You need to compile them before using it. It also has gulp and grunt plugins for setting up a workflow. For better explanations read the documentations on browserify.org.

Why can I not use a variable as parameter in the require() function of node.js (browserify)?

I tried something like:
var path = '../right/here';
var module = require(path);
but it can't find the module anymore this way, while:
var module = require('../right/here');
works like a charm. Would like to load modules with a generated list of strings, but I can't wrap my head around this problem atm. Any ideas?
you can use template to get file dynamically.
var myModule = 'Module1';
var Modules = require(`../path/${myModule}`)
This is due to how Browserify does its bundling, it can only do static string analysis for requirement rebinding. So, if you want to do browserify bundling, you'll need to hardcode your requirements.
For code that has to go into production deployment (as opposed to quick prototypes, which you rarely ever bother to add bundling for) it's always advisable to stick with static requirements, in part because of the bundling but also because using dynamic strings to give you your requirements means you're writing code that isn't predictable, and can thus potentially be full of bugs you rarely run into and are extremely hard to debug.
If you need different requirements based on different runs (say, dev vs. stage testing vs. production) then it's usually a good idea to use process.env or a config object so that when it comes time to decide which library to require for a specific purposes, you can use something like
var knox = config.offline ? require("./util/mocks3") : require("knox");
That way your code also stays immediately traversable for others who need to track down where something's going wrong, in case a bug does get found.
require('#/path/'.concat(fileName))
You can use .require() to add the files that you want to access calculating its path instead of being static at build time, this way this modules will be included and when calling require() later they will be found.

Categories

Resources