wix-incubator / react-templates

Light weight templates for react
https://wix.github.io/react-templates
MIT License
2.82k stars 207 forks source link

pluggable architecture #178

Open nippur72 opened 8 years ago

nippur72 commented 8 years ago

react-templates could be modified to accept "plugins" in order to increase its flexibility and extendibility.

For example an user needing a new feature could simply write a plugin in the form of a javascript module and use it to extend the way react-templates process templates.

There could be a "pre" plugin that works on the "DOM" after it's loaded and before it's processed, and a "post" plugin that is applied after the normal process.

The result of compilation should be also accessible with plugins.

erichulburd commented 8 years ago

I was hoping for the exact same functionality when I experienced my #185 issue. Pre/post plugins would solve that issue and many more.

I will likely be open to working on this PR it the community is open to it within the next couple of weeks. I'd close #185 as well.

nippur72 commented 8 years ago

I am already working on a PR for this, but I've put it on hold because there's another PR waiting to be reviewed that introduces lot of changes and I want to avoid merging nightmares.

Let's discuss about the possible API:

The plugin would be specified via command line with:

$ rt ... --plugin mypluginpath

myplugin should be a module that exports the following object:

interface Plugin {
   onBeforeVisit?: (node: CheerioElement) => void;  // before visiting the whole tree
   onAfterVisit?: (node: CheerioElement) => void;   // after visited the whole tree
   onBeforeTag?: (node: CheerioElement) => bool;    // visting a <tag>, before visiting its children, return false to stop visiting nodes
   onAfterTag?: (node: CheerioElement) => void;     // visting a <tag>, after visiting its children
   onStyle?: (node: CheerioElement) => void;        // visting a <style> node
   onText?: (node: CheerioElement) => void;         // visting a text node, node.data holds the text string
   onComment?: (node: CheerioElement) => void;      // visting a <!-- comment --> node

   // possibly also:
   // onAttributeExpression
   // onTextExpression

   // this is triggered after rt does its own visit
   onBeforeCode?: ({
        renderFunction: string      // the render() function as string    
        requirePaths: string[],     // list of paths to import
        AMDArguments: string[],     // argument names for AMD modules
        AMDSubstitutions: string[], // AMD argument renamed to avoid name clashes          
        vars: string[],             // imports 
        name: string                // name to give to render function when AMD or Globals
   }) => void;

   onAfterCode?: (code: string) => string;  // after the code is generated, before it's written to file

   // context object for sharing data among function calls. Comes already filled with:
   context: {
      fileName: string                              // readonly: name of source file
      html: string                                  // readonly: source HTML file as string
      currentNode: CheerioElement                   // readonly: the node currently visiting during `on` events 
   };
}

The only part that needs to be worked on is onBeforeCode() because the actual react-templates code needs refactoring due to how different module systems are emitted (in other words: it's a mess).