Gathering detailed insights and metrics for babel-plugin-as-macro
Gathering detailed insights and metrics for babel-plugin-as-macro
Gathering detailed insights and metrics for babel-plugin-as-macro
Gathering detailed insights and metrics for babel-plugin-as-macro
npm install babel-plugin-as-macro
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
3 Stars
49 Commits
1 Watching
1 Branches
1 Contributors
Updated on 08 Nov 2021
Minified
Minified + Gzipped
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
0%
1
Compared to previous day
Last week
200%
3
Compared to previous week
Last month
0%
6
Compared to previous month
Last year
-30.2%
127
Compared to previous year
3
3
babel-plugin-as-macro
Power of macro in javascript code.
When I was using Next.js, I want to use the y18n module for internationalization. But y18n uses the file system(fs
module) to save words and their meanings. Importing any module that uses the file system is prohibited by next.js. The first solution that I found, was preval module. But my need is more. I want to have a syntax as simple as :
1import React from "react"; 2import /*as macro*/ y18n from "y18n"; 3{/*as macro*/{ 4 y18n = y18n(/* some config */); 5 y18n.setLocal("en") 6 var __ = y18n.__; 7}} 8export default function page() { 9 return ( 10 <div> 11 <p>{__("HELLO WORLD")}</p> 12 <button>{y18n.__n("one button", "%d two button", 2)}</button> 13 </div> 14 ); 15}
You can install this module via npm.
npm install --save-dev babel-plugin-as-macro
Then, you must configure babel with .babelrc
file.
1{ 2 //... 3 // "presets": ["next/babel"], /* Add this line if you want to use with next.js */ 4 "plugin": [ 5 // other plugins that you want to 6 // be executed before this plugin 7 ["as-macro",/*plugin options*/], 8 // plugins that will be executed 9 // after this plugin 10 ] 11}
There are three ways to define a macro. Because of the nature of macro that is not in any scope of your code, we force by default that macro definitions only be possible in the global scope.
You can define macro by importing a module. You must place the comment block /*as macro*/
after import
identifier.
1import /*as macro*/ y18n from "y18n"; 2import /*as macro*/ X,{x1 as y1,x2 as y2} from "anyModule";
The import statement will be deleted from the code.
In the import statement you can use ECMAScript modules(don't use *.jsx
) or node modules. We use esm module for importing ECMAScript modules.
You can define macro by defining variables. You must place the comment block /*as macro*/
after var
identifier.
1var /*as macro*/ y18n = require("y18n")(/*some config*/); 2var /*as macro*/ __ = y18n.__ , str = "some string";
Variable declaration statement will be deleted from the code.
You can run any nodejs code in a macro-block like a macro definition. The syntax of macro-block is a block statement in the global that has a comment block /*as macro*/
at the first and a block statement after that.
1{/*as macro*/{ 2// This block will be run at build time 3}}
You can do anything possible in nodejs in a macro-block. Variables that are defined in macro-block with var
will also be a macro.
1{/*as macro*/{ 2 var y18n = require("y18n"); 3 y18n = y18n(/*some config*/); 4 var __ = y18n.__; 5 console.log("this will be printed at build time"); 6 let x = 1; /* this is not macro because this is 7 a local variable that is only accessible in this block */ 8 while(x<10){ 9 console.log(x); 10 x++; 11 } 12}}
The macro-block will be deleted from the code.
Macro aims to execute some expression and replace the result in the code. Any expression that is a sequence of object memberships, function calls, and tag templates with a macro name as the main object will be caught as a macro expression.
1macroName; 2macroName`this macro is a function`; 3macroName.property.method(some, argument).tagTemplateMethod`some string` 4 .anotherProperty;
The macro expression will be run in nodejs, and the result will be replaced in the code. For replacement we use json-scriptify module.
1var /*as macro*/ m = { x: 1 }; 2{ 3 /*as macro*/ { 4 m.str = "some string"; 5 } 6} 7let obj = m;
1let obj = { 2 x: 1, 3 str: "some string" 4};
1{ 2 /*as macro*/ { 3 var macroFunction = function computeAtCompileTime() { 4 return "Result"; 5 }; 6 } 7} 8console.log(macroFunction()); 9let obj = macroFunction;
1console.log("Result"); 2 3let obj = function computeAtCompileTime() { 4 return "Result"; 5};
All occurrences of a macro name, except variable definition, will be caught as macro expression. This can bite you.
1var /*as macro*/ m1 = "this is a macro", 2 m2 = "this is another macro"; 3var f = function double(m1) { 4 let m2 = 2 * m1; 5 return m2; 6};
1var f = function double("this is a macro") { 2 let m2 = 2 * "this is a macro"; 3 return "this is another macro"; 4};
The plugin option is an object. You can access values in this object by info tool.
followScopes
is a boolean option that is false
by default. If you set this option to true
, you can use macro-block or define macro variables in any scope. Then, macros only available in that scope.
1var /*as macro*/ m1 = "this is a macro", 2 m2 = "this is another macro"; 3var f = function double(m1) { 4 { 5 /*as macro*/ { 6 var localMacro = "this is local"; 7 } 8 } 9 let m2 = 2 * m1; 10 var str = localMacro; 11 return m2; 12}; 13var globalString = localMacro;
1var f = function double(m1) { 2 let m2 = 2 * m1; 3 var str = "this is local"; 4 return m2; 5}; 6var globalString = localMacro;
But, why we don't set followScopes
to true
by default? Because people may have mistakes like bellow.
1if (bool) { 2 var /*as macro*/ m = "bool is true"; 3} else { 4 var /*as macro*/ m = "bool is false"; 5} 6var string = m;
1if (bool) { 2} else { 3} 4var string = "bool is false";
Regardless of variable bool
, string
is always "bool is false"
. Because both macro definitions are executed and the second definition overwrites first. Moreover, macros are executed at build time when bool
has not been evaluated.
If you want to have some information about the file in which macros are defined and executed in, You can use info
. You can import it from babel-plugin-as-macro/info
in any module and use it.
For example, you can have conf.js
module that detects some config, like language, from the file path.
1// conf.js 2var info = require("babel-plugin-as-macro/info"); 3let someConfigurations = decideFrom(info.absolutePath); 4module.exports = someConfigurations;
Then, you can use this module as macro in your code.
1// main.js 2import /*as macro*/ conf from "./conf.js"; 3/* do something with conf */
info
is an object that will be filled by this plugin when the plugin start.
1info = { 2 options, // plugin options 3 filename, // the name of file or "unknown" if has transformed from string 4 root, // path to root of the project(directory of package.json) 5 absoluteDir, // absolute path to the file directory 6 relativeDir, // path to the directory relative to the root 7 envName //process.env.BABEL_ENV || process.env.NODE_ENV || "development" 8};
MIT
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
license file detected
Details
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More