Getting closure-compiler and Node.js to play nice

前端 未结 5 1717
清酒与你
清酒与你 2020-12-05 10:04

Are there any projects that used node.js and closure-compiler (CC for short) together?

The official CC recommendation is to compile all code for an application toget

5条回答
  •  广开言路
    2020-12-05 10:33

    I replaced my old approach with a way simpler approach:

    New approach

    • No require() calls for my own app code, only for Node modules
    • I need to concatenate server code to a single file before I can run or compile it
    • Concatenating and compiling is done using a simple grunt script

    Funny thing is that I didn't even had to add an extern for the require() calls. The Google Closure compiler understands that automagically. I did have to add externs for nodejs modules that I use.

    Old approach

    As requested by OP, I will elaborated on my way of compiling node.js code with Google Closure Compiler.

    I was inspired by the way bolinfest solved the problem and my solution uses the same principle. The difference is that I made one node.js script that does everything, including inlining modules (bolinfest's solution lets GCC take care of that). This makes it more automated, but also more fragile.

    I just added code comments to every step I take to compile server code. See this commit: https://github.com/blaise-io/xssnake/commit/da52219567b3941f13b8d94e36f743b0cbef44a3

    To summarize:

    1. I start with my main module, the JS file that I pass to Node when I want to run it.
      In my case, this file is start.js.
    2. In this file, using a regular expression, I detect all require() calls, including the assignment part.
      In start.js, this matches one require call: var Server = require('./lib/server.js');
    3. I retrieve the path where the file exists based on the file name, fetch its contents as a string, and remove module.exports assignments within the contents.
    4. Then I replace the require call from step 2 with the contents from step 3. Unless it is a core node.js module, then I add it to a list of core modules that I save for later.
    5. Step 3 will probably contain more require() call, so I repeat step 3 and 4 recursively until all require() calls are gone and I'm left with one huge string containing all code.
    6. If all recursion has completed, I compile the code using the REST API.
      You could also use the offline compiler.
      I have externs for every core node.js module. This tool is useful for generating externs.
    7. I preprend the removed core.js module require calls to the compiled code.

    Pre-Compiled code.
    All require calls are removed. All my code is flattened.
    http://pastebin.com/eC2rVMiN

    Post-Compiled code.
    Node.js core require calls have been prepended manually.
    http://pastebin.com/uB8CaejN


    Why you should not do it this way:

    1. It uses regular expressions (not a parser or tokenizer) for detecting require calls, inlining and removing module.exports. This is fragile, as it does not cover all syntax variations.
    2. When inlining, all module code is added to the global namespace. This is against the principles of Node.js, where every file has its own namespace, and this will cause errors if you have two different modules with the same global variables.
    3. It does not improve the speed of your code that much, since V8 also performs a lot of code optimizations like inlining and dead code removal.

    Why you should:

    1. Because it does work when you have consistent code.
    2. It will detect errors in your server code when you enable verbose warnings.

提交回复
热议问题