Creating JavaScript modules with Babel and ES7

Creating JavaScript modules with Babel and ES7

Last year, a new version of JavaScript was released with a lot of new goodies. One of them was that the syntax for importing and exporting modules was codified as the "only way" to handle JavaScript modules. Well, it's finally here. Another good thing is that it's organized in a way that you can statically analyze the entire module dependency tree. Pretty cool.

Let's take a look at the syntax:

  1. import v from "mod" ;
  2. import * as obj from "mod" ;
  3. import {x} from "mod" ;
  4. import {x as v} from "mod" ;
  5. import   "mod" ;
  6.  
  7. export   var v;
  8. export   default   function f(){};
  9. export   default   function (){};
  10. export   default 42;
  11. export {x};
  12. export {x as v};
  13. export {x} from "mod" ;
  14. export {x as v} from "mod" ;
  15. export * from "mod" ;

So, basically you can import the main value of a module ("default"), or a specific property from explicit exports, or a combination of both, or anything else. Correspondingly, you can export a value for the default module, or an object with multiple properties. You can also export properties one by one. ***Please refer to the style guide for style ;)

ES7 also adds some small additions to this kind of syntax.

  1. export * as ns from "mod" ;
  2. export v from "mod" ;

Nothing special, but when can we use them? We'll have to wait and see. Just like many ES6 syntax features, if you don't plan to support them now, you can use a tool called Babel to transpile them back to ES5. Once you are ready to support them, you can stop Babel from transpiling.

Let's take a look at how this works. We'll implement this in Node.js and NPM. Try executing this file;

src/letter_keys.js

  1. // you would have a constant for each key  
  2. // (I would normally uppercase all constants)  
  3. const a = 119;
  4. const d = 100;
  5. const s = 115;
  6. const w = 119;
  7.  
  8. // you would export all keys here  
  9. // note: you can't say `w: 119` here. It just isn't valid.  
  10. // This destructures to `w: w, a: a, ...`  
  11. export {
  12. w,
  13. a,
  14. d,
  15. s,
  16. }

src/arrow_keys.js

  1. const UP = 38;
  2. const RIGHT = 39;
  3. const DOWN = 40;
  4. const LEFT = 37;
  5.  
  6. export {
  7. UP,
  8. RIGHT,
  9. DOWN,
  10. LEFT,
  11. }

src/move.js

  1. export {a, w, s, d} from './letter_keys' ;
  2. export * as ARROWS from './arrow_keys' ;

The assumption is that the main index.js file is used for the export of the internal module contents, and it assumes that these keys are exported from other files. This example is a bit convoluted, but that's okay.

src/index.js

  1. import * as keys from './move' ;
  2. console.log(keys);

This can be used as part of a project that depends on this module. It should print the awsd key and the arrow object. Let's start with npm. Create the repo dir and initialize it:

  1. ~$ mkdir foo
  2. ~$ cd foo
  3. ~/foo$ mkdir src
  4. # put src files above in ~/foo/src  
  5. ~/foo$ npm init -yes
  6. ~/foo$ npm install babel-cli babel-preset-es2015 babel-preset-stage-1 -D

This will take a while. As you might have guessed, babel-cli supports running Babel from the command line (6), and the babel-preset-stage-1 package provides the relevant ES7 module transpilation tools (at the time of writing). The -yes flag will cause npm to create a default package.json without asking the user. The -D flag is short for --save-dev, and will add the package to the devDependency entry in package.json. Now, add the preset parameters to the default babel configuration file:

.babelrc

  1. {
  2.    "presets" : [ "es2015" , "stage-1" ]
  3. }

If this works, great! hello, future! However, at the time of writing, none of these examples will work in ES6, let alone Node.js. After these transpilation steps, they can be executed anyway.

You should now have an almost empty package.json file that contains the three dev dependencies we added. Let's add a script to this package.json file to enable transpilation:

  1. ...
  2.    "scripts" : {
  3.      "test" : "echo " Error: no test specified " && exit 1" ,
  4.      "translate" : "node_modules/babel-cli/bin/babel-node.js src/index.js"  
  5. },
  6. ...

(Just add the "translate" line and the comma after the "test" line).

This transpilation script is a compilation step. At the end of the article, you can find the final package.json file used in this article (official version). Now, all that’s left is to call npm to run the script to transpile and run our code.

  1. ~/foo$ npm run translate --silent
  2.  
  3. { A: [Getter],
  4. W: [Getter],
  5. S: [Getter],
  6. D: [Getter],
  7. ARROWS: { UP: 38, RIGHT: 39, DOWN: 40, LEFT: 37 } }

Go for it! Now, as a bonus, we can use Jscrambler to "obfuscate" the code a bit. We can pass Babel transpiled code, so why not?

Our (final) package.json file looks like this:

package.json

  1. {
  2.    "name" : "foo" ,
  3.    "version" : "1.0.0" ,
  4.    "description" : "" ,
  5.    "main" : "index.js" ,
  6.    "scripts" : {
  7.      "test" : "echo " Error: no test specified " && exit 1" ,
  8.      "translate" : "node_modules/babel-cli/bin/babel-node.js src/index.js"  
  9. },
  10.    "keywords" : [],
  11.    "author" : "Your Name <[email protected]> (http://localhost/)" ,
  12.    "license" : "ISC" ,
  13.    "devDependencies" : {
  14.      "babel-cli" : "6.6.5" ,
  15.      "babel-preset-es2015" : "6.6.0" ,
  16.      "babel-preset-stage-1" : "6.5.0" ,
  17.      "jscrambler" : "0.7.5"  
  18. }
  19. }

Complete the configuration as usual (if you are using Node.js, you will need a pro account). Here are the files I used

.jscramblerrc

  1. {
  2.    "keys" : {
  3.      "accessKey" : "See https://jscrambler.com/en/account/api_access" ,
  4.      "secretKey" : "See https://jscrambler.com/en/account/api_access"  
  5. },
  6.    "params" : {
  7.      "constant_folding" : "%DEFAULT%" ,
  8.      "dead_code" : "%DEFAULT%" ,
  9.      "dead_code_elimination" : "%DEFAULT%" ,
  10.      "dictionary_compression" : "%DEFAULT%" ,
  11.      "dot_notation_elimination" : "%DEFAULT%" ,
  12.      "function_outlining" : "%DEFAULT%" ,
  13.      "function-reorder" : "%DEFAULT%" ,
  14.      "literal_duplicates" : "%DEFAULT%" ,
  15.      "literal_hooking" : "2;8" ,
  16.      "member_enumeration" : "%DEFAULT%" ,
  17.      "mode" : "nodejs" ,
  18.      "rename_local" : "%DEFAULT%" ,
  19.      "string_splitting" : "0.3" ,
  20.      "whitespace" : "%DEFAULT%"  
  21. }
  22. }

Let's summarize it with a script. This script will translate the source files with Babel, output to the /build folder, then use Jscrambler to obfuscate the code, and then put the result into the /dist folder. The content in /dist can be run normally without using any ES7 features.

run.sh

  1. #!/bin/sh  
  2.  
  3. echo "Babelifying src/*.js"  
  4. node_modules/babel-cli/bin/babel.js -d build src/*.js
  5. echo "Scrambling build/*.js"  
  6. node_modules/jscrambler/bin/jscrambler -o dist build/src/**
  7. echo "Clean up artifacts"  
  8. mv dist/build/src/* dist/
  9. rmdir dist/build/src
  10. rmdir dist/build
  11. echo "Done! See dist/scrambled.js"  
  12. echo "Running:"  
  13. node dist/index.js

Make it ready:

  1. chmod +x run.sh

Next, run:

  1. ~/foo$ ./run.sh
  2. Babelizing src/*.js
  3. src/arrow_keys.js -> build/src/arrow_keys.js
  4. src/index.js -> build/src/index.js
  5. src/letter_keys.js -> build/src/letter_keys.js
  6. src/move.js -> build/src/move.js
  7. Scrambling build/*.js
  8. Clean up artifacts
  9. Done! See dist/ for your scrambled files
  10. Running:
  11. { a: [Getter],
  12. w: [Getter],
  13. s: [Getter],
  14. d: [Getter],
  15. ARROWS: { UP: 38, RIGHT: 39, DOWN: 40, LEFT: 37 } }

You can go to the /dist folder to see the result. You will see that the result is far from the original file, this is because we protected it through Jscrambler, but the result is still runnable.

This concludes the tutorial. Have fun using ES7!

OneAPM helps you easily identify the performance bottleneck of Node.js applications, and analyzes layer by layer through powerful Trace records until the line-level problem code is identified. It displays the system response speed from the user's perspective and counts user usage by region and browser.

<<:  FastQuery: a framework for fast data operations

>>:  What do you need to know to ensure mobile app quality?

Recommend

No teeth, bald buttocks, big pectoral muscles, why modern birds look so weird

Confucius would never have imagined that his name...

About 81% of iPhones are now running iOS 16

Apple's iOS always arrives on devices faster ...

White is not the base color of the earth!

As my country's urbanization and modernizatio...

The growth formula of Liu Genghong's live broadcast room

Recently, Liu Genghong’s live broadcast has becom...

Personal Trainer Nutritionist Online Course

Personal trainer nutritionist online course resou...

Was the crocodile that Han Yu drove away the Han Yu crocodile?

In 819 AD, during the reign of Emperor Xianzong o...

The chat tool is here! Baidu Input Method 10.0 version is released

In order to improve everyone's input efficien...

How does Snapchat survive amid competition from Facebook and other products?

Snapchat has been facing pressure from a number o...

Spring Festival Marketing Case: "I'll Treat You to New Year's Eve Dinner"

The end of 2018 is quietly approaching. After a b...

3 steps to growth hacking

In recent years, the concepts of growth have emer...

Inventory of low-cost traffic-generating methods, 4 major rules!

This article briefly summarizes the three major t...

Heshan SEO training: Summary of 7 principles for website content optimization

From a micro perspective, website content include...