`
yiminghe
  • 浏览: 1460254 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Customize module compiler using closure compiler

阅读更多

                                                                              yiminghe at gmail.com

    Because there rarely exists articles on this topic, I will write in English, this article can also be found at Google Doc . Forgive my chinglish and syntactic error if you are interested.

 

Preface

About how to use closure compiler, you can refer to: 使用closure compiler高级模式

About module, you can refer to : 模块加载模块设计

 

Part 1: Introduction

    In this article, I will show how to customize your own module compiler using closure compiler’s APIs provided.

 

Goals

 

Combiner

 

Scene

 

    There exists some modules, they may depend on each other, but cyclic dependence will be left for later discussion.

For example:

Event module in event.js:

 

KISSY.add(“event”,function(){

  //do your stuff and return event module

   return xx;

},{

 requires:[”event/base”,”event/ie”]

});

 


event/ie module in event/ie.js :

 

KISSY.add(“event/ie”,function(){

    //do your stuff and return event/ie module

    return yy;

     },{

    requires:[“event/base”]

      });
 


     There also exists dom, dom/ie …. , infrastructure module and some UI modules, complicated UI modules may depend on dom, event and infrastructure module.

 

Expected


     This combiner tool can generate file with modules you want exactly, no more and no less. for example : if you want a simple slide ui module ,and this module only depends on dom and infrastructure, it simply shows some effect (no interaction),so event module is not needed ,you can run :

    combiner requires=slide output=slide_standalone.js

     Done! That’s it. slide_standalone.js is generated, and only includes dom/ie, dom, infrastructure, slide in one file .Invoker does not need to know which depends on which . At the same time it can accelerate your application (less http connection);

 

Compiler

 

Scene

    If you look closely at the above part, you will notice some information redundancies, for example: a module file is named as dom.js, and in this file, you have to say

 

  KISSY.add(“dom”,function(){},{…});
 


It would be better: if in dom.js:

 

  KISSY.add(function(){},{…})
 


      The module’s name is same with module’s file name.  If dom.js only contains dom module, it’s fine, some module loaders can solve this problem by attaching file name with module name when loading module files dynamically. But when you combine dom.js with some other module into one file, it’s impossible to associate a single module’s factory function with corresponding module name.

 

Expected


     This tool will automatically transform original module definition code by adding module name which can be obtained from module’s file name.

For example: dom.js contains dom module:

 

KISSY.add(function(){},{requires:[“dom/base”,”dom/ie”]});

 


After transformation, the code will be:

 

KISSY.add(“dom”,function(){},{requires:[“dom/base”,”dom/ie”]});
 


“dom” comes from dom.js

Now you can be free to use combiner to combine multiple modules into one file.

 

Part 2: Using closure compiler


     Closure compiler provides some unpublished APIS, they can be used to customize your own module compiler, it means you do not need to code everything from scratch ,such as lexical, syntactic parser (actually closure compiler does not code from scratch neither, it uses rhino but exports a set of better API) and serialize.

 

Parse


     The first thing is parsing, if you want to do code analysis, you have to parse code to an AST(abstract syntax tree ). In closure compiler it does not provide a simple api (or I missed) ,here is what i do :

 

/**

     * get root node of ast from javascript source string

     *

     * @param {String} code    javascript source

     * @return {Node} root    node of ast corresponding to source code

     */

    public static Node parse(String code) {

        //just want to use Compiler as one parameter for CompilerInput's getAstRoot method

        Compiler compiler = new Compiler();

        CompilerOptions options = new CompilerOptions();

        // Advanced mode is used here, but additional options could be set, too.

        CompilationLevel.WHITESPACE_ONLY.setOptionsForCompilationLevel(

                options);

        compiler.initOptions(options);

        //get a fake file representing input source code

        //CompilerInput need JSSourceFile as type of input for constructor

        JSSourceFile input = JSSourceFile.fromCode("parse.js", code);

        CompilerInput ci = new CompilerInput(input);

        //here we go , finally get root node of ast

        return ci.getAstRoot(compiler);

    }
 



For example (from closure compiler’s wiki)

 

x=’string’
 



AST correspond to the above code :

 



     After you get AST ,you can do anything about this tree ,just as DOM tree with different operation API. In reality closure compiler applies multiple optimization passes to AST and changes it dramatically in the end.

 

Serialize


     Finally AST is ready, you want to serialize it to code file, I still do not find a direct way, it seems closure compiler associates everything with Compiler class. I have to construct a Compiler Object:

 

/**

     * get javascript source from root node of its ast

     *

     * @param {Node} jsRoot root node of javascript source's abstract syntax tree

     * @return {String} corresponding javascript source

     */

    public static String toSource(Node jsRoot) {

        //here,just want Compiler's toSource method

        Compiler c = new Compiler();

        CompilerOptions options = new CompilerOptions();

        //just need option,no real effect

        CompilationLevel.WHITESPACE_ONLY.setOptionsForCompilationLevel(

                options);

        options.prettyPrint = true;

        c.initOptions(options);

        Compiler.CodeBuilder cb = new Compiler.CodeBuilder();

        //finally can get source code by ast

        c.toSource(cb, 0, jsRoot);

        return cb.toString();

    }

 

Part 3: Customize module compiler


This part is short. Because it simply combines the above two parts together:

1. Read code file and transform it to AST, add the missing module name by module’s file name.

2. Track current module’s dependencies and recursively process them.

3. After solve current module’s dependencies, serialize current module’s final AST to file.

4. If you want, you can call closure compiler’s optimization method or just leave it to external invoke later.

 

Part 4: Usage

To Be Continued

Part 5: Summary


     Using closure compiler you do not need to code everything from scratch, you can also process code file deeply according to your own business logic.

     I hope there will be more articles about closure compiler’s implementation. It’s a fantastic library for F2E.

 


 

  • 大小: 65.2 KB
分享到:
评论

相关推荐

    Customize Rules 使用 myrules

    Customize Rules 使用附件中的 myrules 中的内容覆盖 Customize 的内容然后保存

    Customize SharePoint 2010 List Forms Using SharePoint Designer

    ### 使用SharePoint Designer定制SharePoint 2010列表表单 #### 主讲人简介: 本次分享由Asif Rehmani主讲,他是一位资深的SharePoint Server MVP、微软认证讲师(MCT),同时也是SharePoint培训及解决方案架构师。...

    Getting Started with OpenCart Module Development

    Getting Started with OpenCart Module Development gives you step-by-step explanations and illustrations on how to clone, customize, and develop modules and pages with OpenCart. This book shows you how...

    基于深度学习框架的高速路上车流量的实时统计

    2:#customize_compiler_for_nvcc(self.compiler) 110行 2、执行Makefile文件中的 python setup.py ,build_ext --inplace 3、注释掉nms_wrapper.py中的 17行 # from nms.gpu_nms import gpu_nms #

    前端开源库-customize-engine-handlebars

    《前端开源库 Customize Engine Handlebars 深度解析》 在现代前端开发中,自定义引擎扮演着重要的角色,它们允许开发者根据特定需求定制化处理模板、数据和逻辑。其中,“customize-engine-handlebars”是一个专注...

    PaxCompiler_v2.1_27nov08 full source

    TPaxCompiler, TPaxProgram and TPaxPascalLanguage are Delphi components that allows you to embed the paxCompiler into Delphi, Kylix or Borland C++ Builder application so you can customize and extend ...

    customize-tabwidget.zip

    在压缩包中的`customize-tabwidget`文件可能是项目的主要源代码文件,包含实现上述功能的C++代码。开发者可能使用了Qt Creator作为IDE,编写了`.cpp`和`.h`文件,定义了自定义的`TabWidget`类,并在`main.cpp`中实例...

    [iOS开发教程-2]Customize that UIViewCell – Part 1: Using Interface Builder

    在"[iOS开发教程-2]Customize that UIViewCell – Part 1: Using Interface Builder"这篇教程中,我们将深入探讨如何利用Interface Builder来设计并定制自定义的UITableViewCell。 首先,Interface Builder是Xcode...

    Building Tools with GitHub Customize Your Workflow mobi

    Building Tools with GitHub Customize Your Workflow 英文mobi 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    解决myeclipse2014版本中不能启动customize perspective的替换补丁

    然而,软件在使用过程中难免会出现一些问题,比如标题所提到的“不能启动Customize Perspective”就是一个常见的故障。本文将详细解析这个问题及其解决方案。 "Customize Perspective"是Eclipse和MyEclipse中的一个...

    myeclipse_2014_customize_perspective修复bug

    标题 "myeclipse_2014_customize_perspective修复bug" 指向的是一个针对MyEclipse 2014版本中自定义透视图(perspective)问题的修复工具包。MyEclipse是一款功能丰富的Java集成开发环境(IDE),它是Eclipse的商业...

    customize sort.txt

    customize sort.txt

    Building Tools with GitHub Customize Your Workflow 无水印pdf

    Building Tools with GitHub Customize Your Workflow 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,...

    前端开源库-customize

    【标题】"前端开源库-customize"涉及到的核心概念是前端开发中的自定义化框架,它为开发者提供了一种创建可定制引擎的能力。在现代Web应用中,为了满足不同项目的需求和提升用户体验,开发者往往需要对现有的开源库...

    customize_service.py

    customize_service.py

    微软数据库考试70-768: Exam Ref 70-768 Developing SQL Data Models

    Module 6: Customizing Cube FunctionalityThis module describes how to customize a cube.Lessons Implementing Key Performance Indicators Implementing Actions Implementing Perspectives Implementing ...

    前端开源库-customize-engine-uglify

    《前端开源库 Customize Engine Uglify 深度解析》 在前端开发中,优化代码是提高网页性能的关键环节之一。其中,代码压缩是优化的重要手段,它能显著减少文件大小,加快页面加载速度。而`customize-engine-uglify`...

Global site tag (gtag.js) - Google Analytics