Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

Sencha Cmd学习笔记

29
Nov
2016

Sencha Cmd学习笔记

By Alex
/ in JavaScript
/ tags Cordova, ExtJS
0 Comments
简介

Sencha Cmd是一套跨平台的命令行工具,用于支持整个ExtJS开发的生命周期。它包含以下功能:

  1. 代码生成工具:可以生成整个应用程序,并且使用MVC模式扩展应用程序
  2. JS编译器:此编译器理解Sencha的ExtJS/Touch框架,可以减少应用程序加载时间
  3. Web服务器:一个轻量级的,开发用Web服务器
  4. 包管理系统:分布式的包管理系统,可以方便的集成其它用户开发的、发布到Sencha Package Repository的包(例如ExtJS主题)到当前应用程序
  5. 工作区管理:辅助跨越多个应用的框架、包、代码共享
  6. 构建脚本:自动生成应用的构建脚本,并且暴露before、after扩展点
  7. 支持与Cordova/Phone集成
  8. 图形捕获:为支持遗留浏览器,可以将CSS3特性转换为图片
  9. 优化工具:强大的代码选择工具,用于微调、确定哪些被包含在最终的构建中;确定跨越多个页面的公共代码并共享
  10. 灵活的配置系统
  11. 日志系统:详尽的日志,让你可以了解命令的内部工作步骤
命令
命令格式
Shell
1
2
3
4
# 一般命令调用格式
sencha [category] [command] [options...] [arguments...]
# 帮助
sencha help [module] [action]
常用选项
选项 说明
--debug
--info
--quiet
设置调试日志的级别
--quiet  仅仅显示警告、错误
--strict 把警告作为错误看待
--plain 禁止调试日志中的高亮
--beta 启用Beta版本的包仓库
--cwd 设置命令执行的“当前目录”
--nologo 禁止输出版本信息
--sdk-path 对于非app类子命令,指定ExtJS SDK的目录
--time 显示命令的执行耗时
常用子命令
app

这类子命令执行多种应用程序的构建处理:

命令 说明
upgrade 自动生成的应用程序中,有两类文件与Cmd有关:构建脚本(scaffold)、ExtJS/Touch SDK。偶尔的情况下,你需要更新这些内容:
Shell
1
2
3
4
# 仅仅更新scaffold:包括.sencha子目录中的内容,以及app.js等文件
sencha app upgrade
# path-to-new-framework为可选,用于在更新scaffold的同时更新你使用的ExtJS的版本
sencha app upgrade [ path-to-new-framework ]
init 初始化当前目录为一个Sencha Cmd应用程序,可以从空白目录开始:
Shell
1
sencha app init --ext=/path/to/extjs/ AppName --modern
install 确保不完整的Sencha Cmd应用程序变得可以运行(补充缺失的文件):
Shell
1
sencha app install --frameworks=/path/to/extjs
build 构建应用程序:
Shell
1
2
# 基于开发环境构建
sencha app build development
refresh 执行部分构建,仅仅构建脚本相关的部分
generate

生成模型、控制器或者其它组件,甚至整个应用程序:

命令 说明
app 生成一个起步应用程序:
Shell
1
2
sencha generate app -ext -classic AppName ./AppPath
sencha -sdk /home/alex/JavaScript/extjs/6.2.0 generate app -modern AppName ./AppPath
controller 为当前应用程序生成一个控制器:
Shell
1
sencha generate controller Central
form 为当前应用生成一个表单,仅Touch
model 为当前应用生成一个模型:
Shell
1
2
3
# 在应用根目录执行
# 生成一个名为User的模型,包含3个字段
sencha generate model User id:int,name,email
package 生成一个起步的本地包,存放到packages/local下:
Shell
1
sencha generate package pkgname
profile 为当前应用程序生成一个配置,仅Touch
theme 为slice操作生成一个主题页面,仅ExtJS
view 为当前应用程序生成一个视图相关组件
Shell
1
2
# 在view/foo子目录下生成Thing视图,以及视图模型ThingModel、视图控制器ThingController
sencha generate view foo.Thing
workspace 生成一个新的工作区
repository

这一类子命令用于管理包的远程仓库:

命令 说明
list 列出可用的远程仓库
add 添加一个远程仓库:
Shell
1
sencha repository add sencha http://cdn.sencha.com/cmd/packages/
remove 删除一个远程仓库
其它子命令
命令 说明
upgrade 升级Sencha Cmd本身。示例:
Shell
1
2
3
4
5
6
7
8
# 检查新版本
sencha upgrade --check
# 执行升级
sencha upgrade
# 无人值守的升级
sencha upgrade --unattended
# 包含beta版本
sencha upgrade --check --beta 
与ExtJS6联用
生成应用

可以使用下面的命令生成一个Universal应用的脚手架:

Shell
1
sencha -sdk /home/alex/JavaScript/extjs/6.2.0 generate app MyApp MyApp

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.
├── app                   # 当前应用有关文件的目录
│   ├── Application.js    # 当前应用的实现类,扩展Ext.app.Application
│   ├── model             # 视图模型、模型存放目录
│   ├── store             # 存储存放目录
│   └── view              # 视图控制器、控制器存放目录
├── app.js                # 应用入口点定义
├── app.json              # 应用描述符文件
├── bootstrap.js          # 自举文件,其中包含微加载器
├── build                 # 构建结果存放目录
│   ├── development       # 构建环境:development的构建结果
│   └── temp
├── build.xml
├── classic               # 针对classic toolkit的源代码
│   ├── sass
│   └── src               # 组件,主要是UI组件
├── ext                   # 复制来的ExtJS SDK完整目录
├── index.html            # 入口点网页
├── modern                # 针对modern  toolkit的源代码
│   ├── sass
│   └── src               # 组件,主要是UI组件
├── overrides             # 对组件的重写存放在此
├── packages              # 依赖的包存放在此
├── resources             # 资源文件存放在此
├── .sencha
│   ├── app
│   │   ├── defaults.properties   # 构建属性的默认值和说明
│   │   ├── development.defaults.properties # 针对构建环境development的默认构建属性
│   │   ├── development.properties # 针对构建环境development的构建属性
│   │   ├── ext.properties  # 针对ExtJS的构建属性
│   │   ├── sencha.cfg      # Sencha Cmd配置文件
└── workspace.json        # 工作区描述符文件
构建应用

执行下面的命令构建当前应用:

Shell
1
sencha app build

该命令会构建你的HTML页面、JS代码和主题到build目录中。

开发者模式

Sencha Cmd根据你的app.json,生成自举脚本(bootstrap)。自举脚本向动态类加载器(Ext.Loader以及微加载器)传递必要的信息,后者负责加载程序代码。自举脚本不会被你的JS代码的变动影响,因此你需要执行编辑 - 保存 - 重新载入 这样的工作流程。

要保证自举脚本与最新的源码文件匹配,可以基于以下两种途径之一:

  1. 使用 sencha app watch ,该命令启动一个Web服务器,并且监控源码,在源码改变后立即执行一次开发环境构建(development build)。该方式支持Fashion的Live Update功能
  2. 手工构建并更新:
    Shell
    1
    2
    3
    4
    # 除了更新JS部分,还继续样式的编译,并生成CSS
    sencha app build development
    # 仅仅更新bootstrap与JS相关的部分
    sencha app refresh
Fashion

Cmd 6引入了此组件,用于支持快速开发ExtJS 6主题。联合使用app watch可以启用所谓实时更新(Live Update)的特性。

实时更新利用Fashion来编译Scss,并且将其生成的最新CSS注入到浏览器页面。Fashion基于JavaScript实现,不需要Ruby的支持。

Fashion扩展了Sass语言,添加了新的特性,以便Sencha Inspector之类的工具可以可视化的查看、编辑主题、应用中定义的变量。

启用实时更新

配置app.json以启用实时更新:

JavaScript
1
2
3
4
5
"development": {
    "tags": [
        "fashion"
    ]
},

也可以不指定上述配置,直接修改URL来启用实时更新: ?platformTags=fashion:1  

启用实时更新时,加载到浏览器的是Sass而非生成的CSS,当Sass发生变化时,Fashion会立即编译之并更新页面上的CSS。

动态变量

动态变量是Fashion对Sass的语言扩展。在Fashion中动态变量非常重要,动态变量类似于普通变量,但是其值被 dynamic() 标记包围。动态变量之间的交互方式与普通变量不同:

Sass
1
2
3
4
5
$bar: dynamic(blue);
$foo: dynamic($bar);  // 变量$foo依赖于$bar
$bar: dynamic(red);
 
@debug $foo;  // $foo的值为red而不是blue

可以注意到,动态变量的值并非在逐行处理过程中确定的。对动态变量的处理分为赋值、估算两个阶段。

赋值阶段

赋值阶段的处理类似于普通变量,按照级联的顺序赋值。对动态变量的赋值只能在文件范围(位于任何控制块的外面)进行:

Sass
1
2
3
4
5
6
7
$bar: dynamic(blue);
 
@if something {
    $bar: dynamic(red); // 非法
}
 
$bar: dynamic(if(something, red, blue)); // 合法

这一限制是动态变量估算、提升行为(hoisting behaviors)所需。

在声明之后,再次对动态变量赋值,必须要附带dynamic():

Sass
1
2
3
4
$bar: dynamic(blue);
$bar: red;  // bar被赋值为red
$bar: green !default;  // 重新赋值为green
@debug $bar;   // green
估算阶段

在该阶段,根据依赖顺序(而不是声明顺序)确定动态变量的实际值,例如:

Sass
1
2
$bar: dynamic(mix($colorA, $colorB, 20%));
$bar: dynamic(lighten($colorC, 20%));

由于对$bar进行了再次赋值,$bar依赖于$colorC,因此仅当$colorC的值被估算出来后,$bar的值即可确定,至于$colorA、$colorB何时估算,与$bar无关。

Hoisting

为了实现估算阶段的逻辑,Fashion收集所有动态变量,在执行任何Sass代码之前统一的估算它们。这意味着类似于JavaScript变量,Fashion动态变量也是被提升到作用域最前面的。

Elevation

当一个变量用于给动态变量赋值,其本身也被升级为动态变量:

Sass
1
2
$foo: blue;   // 尽管$foo作为普通变量声明,但是由于动态变量$bar依赖于它,因此$foo被升级为动态变量
$bar: dynamic($foo);
扩展Fashion

你可以通过编写JS代码来扩展Fashion,要在Sass中包含这些扩展代码,可以:

Sass
1
2
require("my-module");
require("../path/file.js");

在内部,Fashion使用ES6的System.import加载标准的JS模块。

一个扩展的代码可以如下:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ES6以前的版本
exports.init = function(runtime) {
    runtime.register({
        magic: function (first, second) {
        }
    });
};
// ES6
module foo {
    export function init (runtime) {
        runtime.register({
            magic: function (first, second) {
            }
        });
    }
} 
编译器友好代码指南

编译器是Sencha Cmd的主要组件。此编译器并不类似于:

  1. YUI压缩器
  2. Google Closure编译器
  3. UglifyJS

上述工具解决JS开发者面临的不同问题,但是它们不能理解Sencha框架,例如Ext.define用于定义类。

框架知晓

编译器用于提供框架相关的优化、诊断,一旦代码通过了此编译器,其它一般性的工具可以继续处理它。这类优化可以极大的改善ExtJS的加载时间,特别是针对遗留浏览器。

为了编译器能够最优化的操作, 你必须遵循一系列的编码约定,这样编译器才能理解你的代码,进而执行优化操作。

代码组织

Cmd生成的动态加载器,以及之前的JSBuilder,都假设代码按照一定的规则组织。你应该保证:

  1. 每个JavaScript源文件应该在全局作用域包含一个Ext.define 语句
  2. 源文件的文件Base名必须和ExtJS类的Simple name匹配
  3. ExtJS类的命名空间应当映射为源码子目录
  4. 为了让编译器能够自由的在类级别选择代码,应当确保一个类对应一个文件

第2、3两条类似于Java的包与文件系统的映射规则。

类声明

编译器能够识别Ext.define的以下关键字(keywords)并进行优化处理:requires、uses、extend、mixins、statics、alias、singleton、override、alternateClassName、xtype

除了Ext.define最常用的调用方法——第二个参数传递简单对象以外,编译器也能够识别以下几种调用变体:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 指定第二个参数为函数
Ext.define('Foo.bar.Thing', function (Thing) {
    return {
        // 这里声明关键字
        extend: '...',
    };
});
// 指定第二个参数为函数调用
Ext.define('Foo.bar.Thing', function () {
 
    return {
        // 这里声明关键字
        extend: '...'
    };
}());
重写(Overrides)

从ExtJS 4.1/Touch 2.0开始,Ext.define能够管理重写。在历史版本中,重写用于打补丁以解决BUG或者增强功能。在引入动态加载器后,情况变得复杂,因为 Ext.override 的执行需要时间。在大量使用重写的应用程序中,并非所有重写都被所有页面或者build使用。

现在,编译器能够理解重写,以及它们对依赖、加载顺序的影响。在未来的版本中,编译器在消除dead code(被override替换)时会更加激进。遵循本节的规则,你可以在未来版本获得益处。

标准的重写代码范例如下:

JavaScript
1
2
3
4
5
// 尽管这里选定的名字空间是任意的,但是最好遵循下文说明的规则
Ext.define('MyApp.patches.grid.Panel', {
    override: 'Ext.grid.Panel',
    ...
});

通过重写来打补丁是最常见的应用。你应当把所有补丁的命名空间与它针对的目标类的命名空间对应,例如MyApp.patches对应Ext。

除了打补丁,重写还可以用做不完整类(Partial Classes)。当你使用Sencha Architect之类的代码生成器时,一个类通常分类两个部分:机器生成部分、人工编写部分,这种划分有助于机器部分的重新生成。不完整类的用法示例:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 自动生成的类
Ext.define( 'Foo.bar.Thing', {
    // NOTE: This class is generated - DO NOT EDIT...
    requires: [
        'Foo.bar.custom.Thing'
    ],
    method: function () {
    },
} );
// 重写,作为部分类
Ext.define( 'Foo.bar.custom.Thing', {
    override: 'Foo.bar.Thing',
    method: function () {
        this.callParent(); // 调用自动生成的方法
    },
} );

重写的最后一种用法是作为切面(Aspect) 。OOP会导致的一个问题就是过度肥胖的基类,这是因为它包含过多的公共逻辑。使用override,可以分离出其中的逻辑,而仅仅在需要使用的时候,才require之:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 作为切面的重写
Ext.define('Foo.feature.Component', {
    override: 'Ext.Component'
});
// 作为切面的重写,与Foo.feature.Component提供一个产品族
Ext.define('Foo.feature.grid.Panel', {
    override: 'Ext.grid.Panel',
 
    requires: [
        'Foo.feature.Component' // 由于重写不产生继承关系,这里必须显式require
    ]
});
 
 
// 需要使用上述切面的客户代码:
 
requires: [
    'Foo.feature.grid.Panel'
]
// 或者
requires: [
    'Foo.feature.*'
]

注意:在重写时,你可以调用 callSuper() 来绕过对被重写方法的调用,而调用其父版本。

资源文件管理

除了JavaScript、CSS、HTML以外,Web应用程序往往包含很多代码无关的资源文件(也叫资产,Asset)——图片、视频、数据文件。Cmd将这些资产分类并提供多种管理它们的选项。

资源的来源

资源文件一般都放在名为resources的目录下,这些目录可能来自:

  1. 对于单Toolkit应用,位于应用根目录,例如MyApp/resources
  2. 对于Universal应用,位于应用根目录,以及各Toolkit下,例如MyApp/resources、MyApp/classic/resources
  3. 主题附带的资源文件,位于主题的根目录,例如theme-neptune/resources
  4. 软件包附带的资源文件,位于软件包的根目录

你可以应用程序描述符app.json中的resources数组,用来定制应用程序资源的来源:

JavaScript
1
2
3
"resources" [{
    "path": "resources",   // 改变此配置以便在其它目录中存放资源
}]

对于单Toolkit应用,仅该数组的第一个元素作为实际的资源路径,其它元素、第一个元素的output设置都被忽略。 

对于Universal应用,该数组可以指定多个元素,并且使用output来指定使用哪个资源池:

JavaScript
1
2
3
4
5
6
"resources": [{
    "path": "resources",
    "output": "shared"   # 使用shared资源池
}, {
    "path": "${toolkit.name}/resources"   # 使用默认资源池
}],

这样,可以被多个Toolkit共享的资源,就可以放在(默认)应用根目录的resources目录下,而Toolkit独有的资源则放在与Toolkit同名的目录的resources子目录下。

对于包,支持像Universal应用那样声明多个资源目录、使用哪个资源池。

资源的输出

app.json的顶级output元素, 声明在构建后的应用程序文件被输出到何处:

JavaScript
1
2
3
4
"output": {
    "base": "${workspace.build.dir}/${build.environment}/${app.name}",
    // 例如 ./workspace/build/production/MyApp
},

对于Universal应用,可以定义资源池(resource pools):

JavaScript
1
2
3
4
5
6
7
8
9
10
11
"output": {
    "base": "${workspace.build.dir}/${build.environment}/${app.name}",
    // 资源池定义
    "resources": {
        // 默认资源池,对应buildId下的resources目录
        "path": "${build.id}/resources",
        // 名为shared的共享资源池,对应应用程序的根目录下的resources子目录
        "shared": "resources"
    }
 
},

应用、主题、包中的资源文件,都输出到某个资源池中:

  1. 单Toolkit应用、主题中的资源文件,输出到默认资源池
  2. Universal应用,默认的,应用根目录下resources输出到共享资源池;toolkit.name/resources输出到默认资源池
  3. 包的资源输出到资源池的package.name子目录下。这是应用程序构建为包提供的沙盒
资源的覆盖

多个不同来源的资源文件,可能存在路径名相同的情况,此时会按照一定的规则覆盖:

  1. 由于主题支持继承,因此子主题中的同名资源,自动覆盖父主题中的资源
  2. 在应用的resources目录中(如果是Universal应用,则必须是toolkit.name/resources目录中)的文件,可以覆盖同路径的来自主题、包的资源文件
package.json配置

与应用类似,包也具有自己的描述符package.json:

JavaScript
1
2
3
4
5
6
// 构建输出
"output": "${package.dir}/build",
// 资源路径
"resources": [{
    "path": "resources"
}]

为了让非Cmd应用使用包,可以单独构建之: sencha package build  。注意包的构建不区分development/production,其build目录中的东西可以被script、link等元素引用。

包资源与沙盒

为了防止不同包中同名资源被意外的覆盖,应用程序构建(App build)为包中的资源提供沙盒,即,为每个包的资源提供resources的子目录,子目录以包名为名称。

由于应用程序资源、包资源路径处理方式的不同,因此在CSS中引用时,需要注意。Cmd提供了API来获取资源的正确路径:

Sass
1
2
3
4
5
6
.arrow-button {
    // 不使用资源池,或者使用默认资源池时:
    background-image: url(get-resource-path('images/arrow.png'));
    // 使用资源池时:
    background: url(get-resource-path('images/foo.png', $pool: 'shared'));
}

在JavaScript中,也有类似的API:

JavaScript
1
2
3
4
image.setSrc(
    // 第二个参数为资源池的名称
    Ext.getResourcePath('images/arrow.png', null, 'arrow-button')
); 
包管理

Sencha Cmd应用的packages目录包含local、remote两个子目录,分别存放本地、远程包。

你可以在app.json中使用requires声明对包的依赖。sencha app build、sencha app refresh命令会自动把包集成到应用程序中。

本地包

执行下面的命令可以生成一个本地包:

Shell
1
sencha generate package common

此包的内容放置在packages/local/common目录中。此包的packages.json中会自动添加 local: true  配置,该配置可以放置Cmd下载远程包并覆盖此本地包。

远程包

远程包的管理是基于包仓库(package repositories)进行的,Cmd会自动生成一个本地的包仓库,用于缓存、发布包。

执行下面的命令,可以查看可用的远程仓库列表: sencha repository list ,你可以使用 sencha repository add 、 sencha repository remove 命令来添加、删除远程仓库。

包命名规范

sencha-*、ext-*、touch-*、cmd-*这些前缀的包名被内部使用。

版本管理

可以指定当前包的版本号,以及它和什么样的历史版本兼容:

package.json
JavaScript
1
2
3
4
5
6
{
    // 当前版本
    "version": "n.n.n",
    // 兼容的最低版本
    "compatVersion": "2.4.2",
}

在应用描述符的requires里,可以附加版本要求: "requires": [ "ext-easy-button@1.0" ]  。版本要求语法:

示例 说明
-1.2 最高1.2
1.0-
1.0+
最低1.0
1.0-1.2 版本在1.0到1.2之间
1.0-1.2? 版本在1.0到1.2之间,或者1.0-1.2的兼容版本
工作区管理

Cmd引入工作区的概念,以便管理多个需要共享框架、代码、样式、资源的应用程序。

什么是工作区

构建一个大型应用程序的步骤与构建一个单页应用程序的起始步骤一样。一旦应用程序扩展到多个页面,以下常见问题将会出现:

  1. 如何共享的使用同一框架
  2. 如果跨页面共享代码
  3. 如果共享第三方包

为了解决这些问题,Cmd引入了工作区的概念。一个工作区是包含了多个页面(在Sencha的术语里叫应用,Application,因为应用一般都是单页面的,一个应用只进行一次Ext.application调用)、框架(不同版本)、包以及其它共享代码/文件的目录。工作区的根目录通常会纳入版本控制。

如果在工作区内组织各页面的目录并不重要,但是通常把它们的目录作为工作区根目录的直接子目录。

创建工作区

执行下面的命令可以创建一个工作区:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
sencha generate workspace /path/to/workspace
 
# 生成的目录结构如下:
.
├── packages
├── .sencha               # Sencha Cmd相关文件
│   ├── .cvsignore
│   ├── .gitignore
│   └── workspace         # 工作区相关文件
│   ├── plugin.xml
│   └── sencha.cfg        # Sencha Cmd配置
└── workspace.json        # 工作区描述符
微加载器

所谓微加载器(Microloader)是Sencha的数据驱动的JavaScript/CSS动态加载器。微加载器由Cmd提供,并作为生成的应用程序的一部分。

ExtJS 6的微加载器实现与ExtJS 5或者Touch不同,它增强了一些功能,这些功能可以在app.json中配置。执行 sencha app upgrade 时微加载器会被一同升级。

加载Manifest

Cmd会把app.json转换为manifest供微加载器在运行时使用。你也可以在运行时调用 Ext.manifest 获得此manifest的引用。ExtJS6本身利用此manifest完成一些工作,例如兼容性层(Compatibility Layer)。

有三种方式来指定微加载器使用什么Manifest:

  1. 嵌入式Manifest,配置:
    app.json
    JavaScript
    1
    2
    3
    4
    5
    "output": {
        "manifest": {
            "embed": true
        }
    }

     可以在构建期间把Manifest嵌入到bootstrap.js文件中

  2. 命名Manifest,你可以指定从哪个文件中加载Manifest,默认app.json:
    XHTML
    1
    2
    3
    4
    5
    <script type="text/javascript">
        var Ext = Ext || {};
        Ext.manifest = 'foo';  // 从./foo.json加载
    </script>
    <script id="microloader" data-app="f72c0f68" type="text/javascript" src="bootstrap.js"></script>
  3. 动态指定Manifest,你可以动态的设置Ext.manifest为任意字符串为应用描述符文件的basename
Manifest的生成

微加载器负责解析app.json并生成manifest,大概步骤如下:

  1. 读取app.json,其中内容被后续步骤解析
  2. 获取app.json中与当前构建环境(production/testing/development)匹配的设置,作为基础manifest
  3. 获取app.json中与当前构建配置匹配(builds.***)的设置,覆盖上面的manifest
  4. 读取app.json中与当前Toolkit匹配(classic/modern)的设置,覆盖上面的manifest
  5. 读取app.json中与当前packager匹配的设置,覆盖上面的manifest
  6. 开始处理依赖包,如果package.json中声明了js、css,则它们按照包的依赖顺序,插入上面manifest['js']或者manifest['css']数组的最前面。package.json中其它内容被置入manifest的packages属性中
引用微加载器

Cmd生成的脚手架代码中已经引用的微加载器:

XHTML
1
<script id="microloader" data-app="12345" type="text/javascript" src="bootstrap.js"></script>

其中data-app为应用的UUID,该ID会在LocalStorage中作为Key使用,避免多个页面的数据混乱在一起。

应用描述符

由Cmd自动生成的app.json叫做应用描述符,该描述符会被微加载器使用,并且在运行时暴露为 Ext.manifest。你可以定制其中的很多配置项,以改变应用的行为。下表列出最常用的配置项:

indexHtmlPath 应用的HTML文档文件路径,此路径相对于app.json文件。默认值是index.html,可以根据需要修改。修改后应该同时指定output配置
framework 使用什么框架,可选值ext、touch,或者工作区自定义的框架名
theme 对于ExtJS应用,此配置用于指定主题名。例如 "theme": "ext-theme-crisp" 
classpath  指定源码目录。例如:
JavaScript
1
2
3
4
"classpath": [
    "app",
    "${toolkit.name}/src"
] 

js

一个数组,指定需要被微加载器自动加载的JavaScript文件,默认脚手架生成如下内容:

JavaScript
1
2
3
4
"js": [{
    "path": "app.js",
    "bundle": true
}]

上述配置实际上指定了应用程序的入口点。bundle=true意味着此配置条目被构建出的concatenated classes代替。 你可以继续增加配置:

JavaScript
1
2
3
4
5
6
7
"js": [{
    "path": "library.js",
    "includeInBundle": true // 包含在concatenated classes中,如果false,则此文件在构建结果中存在,由微加载器独立加载
},{
    "path": "app.js",
    "bundle": true  // 只能有一个元素定义此属性,设置为true则此文件作为concatenated classes容器
}]

所有JavaScript文件必须按照其执行顺序在此声明

对于应用程序的依赖,应该在requires配置中声明,而不是此配置 

css

一个数组,指定微加载器需要按顺序加载的CSS文件。默认内容:

JavaScript
1
2
3
4
5
6
7
8
9
"css": [
    {
        "path": "${build.out.css.path}",
        "bundle": true,
        "exclude": [
            "fashion"
        ]
    }
],

此默认值仅仅是一个导入sass目录构建结果的存根 

requires 此数组引用应用所依赖的包的名称,当Cmd处理此数组时,会自动下载、抽取缺失的软件包到工作区中。包可以在自己的package.json中声明依赖,这样的传导依赖也会被下载、抽取。你可以同时指定包的版本

output 

控制构建的如何输出、在哪里输出。此配置可以控制构建输出的多个方面。例如,修改indexHtmlPath为../page.jsp后,你需要继续设置output:

JavaScript
1
2
3
4
5
6
"output": {
    "page": {
        "path": "../page.jsp",
        "enable": false // 仅仅说明页面URL是哪个,但是不赋值源文件到输出
    }
}

你可以指定appCache属性,来控制哪些资产可以被浏览器缓存供离线使用:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"output": {
    "appCache": {
        // 启用缓存
        "enable": true
    },
    "appCache": {
        // 哪些使用缓存
        "cache": [
            "index.html"
        ],
        // 哪些必须联网获取
        "network": [
            "*"
        ],
        // 哪些在联网获取失败时使用缓存
        "fallback": []
    }
},

LocalStorage缓存

除了浏览器自带的应用程序缓存(通过appCache配置),微加载器还支持通过LocalStorage缓存每一个资产文件。在尝试进行任何远程获取之前,微加载器会首先使用UUID查询LocalStorage,如果文件没有变化则直接使用缓存,这可以让应用程序的加载变得非常块。微加载器还支持增量补丁——即仅仅资产、CSS、JS变化的比特通过网络下载,然后合并到LocalStorage中。

要启用LocalStorage缓存,你需要逐个设置资产的update属性,取值full表示全量更新,delta表示增量更新:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"js": [
    {
        "path": "app.js",
        "bundle": true,
        "update": "delta"
    }
],
 
"css": [
    {
        "path": "app.css",
        "update": "full"
    }
]

除了在资产上设置update,要让缓存生效,还必须声明全局的cache配置:

JavaScript
1
2
3
"cache": {
    "enable": true
}

在开发阶段,常常把全局缓存设置为false,仅仅在产品构建时才设置为true 

你还可以设置: "cache": { "deltas": true }  这样所有update=delta资产的变化会出现在构建结果的detas目录中,如果设置deltas为字符串,则此字符串对应的目录代替deltas目录的功能

一旦微加载器检测到Application Cache、LocalStorage缓存的内容存在更新,会立即发布全局事件,你可以监听此事件并作出反应:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Ext.application( {
    name: 'MyApp',
    mainView: 'MyMainView',
    // 监听缓存更新事件
    onAppUpdate: function () {
        Ext.Msg.confirm( '应用程序已更新',
            function ( choice ) {
                if ( choice === 'yes' ) {
                    window.location.reload();
                }
            }
        );
    }
} );

builds

此配置用于声明一个或者多个构建配置(Build Profiles)

如果应用程序存在多个变体,你就可以添加一个新的构建配置。例如:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
"builds": {
    "classic": {
        "theme": "ext-theme-classic"
    },
    "gray": {
        "theme": "ext-theme-gray"
    },
    "access": {
        "theme": "ext-theme-access"
    },
    "
}

builds中的每一个属性称为一个构建配置,此属性的值会在执行使用此配置构建时,覆盖app.json中的配置项以生成最终有有效的manifest 

production  /  testing   /  development

对应不同的构建环境(Build Environment)的特定配置信息

classic  /  modern

对应不同的Toolkit的特定配置信息

locales

指定支持的区域配置: "locales": [ "en", "he" ] 。在同时使用builds时,最终的构建配置的名称不再是classic,而是classic-en、classic-he等

tags  

你可以指定多个标记:

JavaScript
1
2
3
4
5
6
7
8
"tags": ["ios", "phone", "fashion"]
// 或者
"tags": {
    "ios": true,
    "phone": true,
    "desktop": false,
    "fashion": true
}

这些标记被检测到后,将覆盖自动检测到的值

集成Cordova/PhoneGap

PhoneGap基于Cordova构建,并提供一些辅助工具,例如远程构建服务。

基于Sencha Cmd构建时,仅能构建DEBUG版本的Cordova/PhoneGap应用,要构建能够在应用商店下载的APP你需要使用Android Studio/XCode。

创建支持Cordova/PhoneGap的应用

首先,按照一般性步骤创建Cmd应用:

Shell
1
2
mkdir MyApp && cd MyApp
sencha app init --ext=/home/alex/JavaScript/extjs/6.2.0 MyApp --universal

当开发ExtJS 6 Universal应用时,则上述生成的应用结构的app.json中已经包含了builds块,这种情况下sencha cordova/phonegap子命令无法修改此块,因此你需要手工的修改:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"builds": {
    "classic": {},
    "modern": {
        "toolkit": "modern",
        "theme": "theme-triton",
        // 如果使用Cordova,可以添加:
        "cordova": {
            "config": {
                "platforms": "ios",
                "id": "cc.gmem.myappid"
            }
        },
        // 如果使用PhoneGap,可以添加:
        "packager": "phonegap",
        "phonegap": {
            "config": {
                "platform": "ios",
                "id": "cc.gmem.myappid"
            }
        }
    }
},

然后进入工程目录,初始化Cordova/PhoneGap支持:

Shell
1
2
3
sencha phonegap init cc.gmem.myappid  MyApp
# 或者
sencha cordova init cc.gmem.myappid MyApp

当开发ExtJS Modern应用程序时,上述命令会自动生成如下builds块:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
// native仅仅是一个构建配置名(build-name),你可以将其修改为任意值
"native": {
    "packager": "cordova",
    "cordova": {
        "config": {
            "platforms": "ios android",  // 需要支持的移动平台
            "id": "cc.gmem.myappid2",    // 用于唯一识别应用程序的标识符
            "name": "MyApp2"             // 应用程序名称
        }
    }
}

上述命令执行完毕后,在工程目录会出现cordova或者phonegap子目录。 这些子目录的内容与普通Cordova/PhoneGap工程一致。

下面的Cmd子命令可以用于构建出Native软件包: 

Shell
1
2
3
4
5
6
7
8
# 首先构建Sencha应用程序,然后构建Native应用
sencha app build {build-name}
# 首先构建,然后尝试在连接上来的设备上运行程序
sencha app run {build-name}
# 首先构建,然后尝试在模拟器上运行程序
sencha app emulate {build-name}
# 构建Sencha应用程序,然后拷贝到Cordova/PhoneGap指定目录,准备后续的Native构建
sencha app prepare {build-name}
开发PhoneGap远程应用

使用PhoneGap远程构建服务,可以避免很多麻烦的问题,例如下载SDK、工具,购买Mac电脑。你仅仅需要把自己的Web应用上传到PhoneGap服务器,Adobe就可以自动的把Native应用生成给你。在开始之前,你需要到PhoneGap网站申请一个免费账号。如果要构建iOS应用,你需要在PhoneGap网站上填写一系列的credentials信息。

要启用远程构建,需要配置app.json:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
"builds": {
    "native": {
        "packager": "phonegap",
        "phonegap" : {
            "config": {
                "platform": "ios",
                "remote": true,  // 远程构建
                "id": "com.mydomain.MyApp"
            }
        }
    }
}

为了向Cmd提供你的PhoneGap网站账号信息,你需要在应用根目录创建一个local.properties文件:

local.properties
INI
1
2
phonegap.username=name@me.com
phonegap.password=passwd

远程构建完毕后,你可以到PhoneGap门户去下载安装包,或者将其发布到应用商店。 

新特性列表
6

新的安装器

此版本的安装程序自带了运行Cmd所需的JRE,并且移除了对Ruby的依赖(由于引入了Fasion)。新的安装器不再需要root权限

如果你使用老的框架版本,例如ExtJS 4/5、Touch2。你还是需要Ruby以及Compass包以便编译Sass代码

Fashion

Fashion是Sencha新开发的,用于其扩展的Sass语言的编译器。Cmd调用Fashion为ExtJS应用程序、主题构建Sass。当使用sencha app watch时,你可以获得实时更新(Live Update)—— 应用程序的CSS自动与最新代码同步,而不需要刷新浏览器

由于引入了Fashion,Cmd不再依赖于Ruby来生成主题

工作区改进

为了支持基于包的代码共享,Cmd6将不同的包分离到子目录中(原先一律放在packages目录):

  1. packages/local:自己在本地生成的包
  2. packages/remote:下载/抽取(extrace)的包。workspace.json中的packages.extract可以修改此默认位置

remote目录可以安全的从CVS中忽略

从Cmd6开始,工作区的根目录存在一个workspace.json文件,此文件应该在CVS中存储

Microloader

微加载器是首先由Touch框架引入的,并且在Cmd 5中开始支持ExtJS 5应用程序

Cmd 6对微加载器进行了改进,添加了基于localStorage的缓存支持,并且可以在app.json中禁用缓存

6.1

框架与工作区管理

当项目规模增大后,在一个工作区中同时开发多个应用程序,并且使用多个ExtJS版本的可能性增加。在6.1之前,一个工作区仅仅可以使用单个版本的ExtJS,则要求所有应用程序必须升级使用的ExtJS版本。

现在,你可以在workspace.json中声明多个ExtJS版本:

JavaScript
1
2
3
4
"frameworks": {
    "ext62": "ext",
    "ext602": "ext-6.0.2"
}

frameworks的每一个子项,其值对应工作区中的一个子目录,其键可以供应用程序的app.json引用:

JavaScript
1
"framework": "ext62"

你可以随时的添加新的框架版本到工作区:

Shell
1
2
3
4
# 自动生成frameworks子项,其键根据目录中ExtJS的版本号推导出,例如6.2.0 版本的键为ext62,6.0.2版本的键为ext602
sencha framework add /path/to/ext
# 手工指定键值  path为拷贝到工作区的哪个子目录,key为键,必须以ext或者touch开头
sencha framework add -key extFiveO -source /path/to/ext-5.0.0 -path ext50

添加完新框架后, 框架的代码会自动拷贝到工作区中。你可以使用新添加的框架,来创建一个应用程序:

Shell
1
sencha generate app -extFiveO AppName path/to/app

执行下面的命令可以删除一个框架版本:

Shell
1
2
# --force 即使有应用程序在使用,也强制删除框架
sencha framework remove --force  extFiveO

可以升级工作区内的应用程序,让其使用特定的框架版本:

Shell
1
2
3
4
5
6
# 从/path/to/ext目录升级以ext作为key的框架
sencha framework upgrade ext /path/to/ext
# 升级单个应用程序
sencha app upgrade ../ext62
# 升级整个工作区中所有应用程序、包中和Cmd相关的文件
sencha workspace upgrade 

在任何时候,你都可以列出当前工作区可用的框架版本:

Shell
1
sencha framework list
6.2

app init子命令

允许初始化当前目录为一个Sencha Cmd应用程序。你可以从空白目录开始,执行下面的命令生成完整的HelloWorld程序结构:

Shell
1
2
# 除了--modern,还可以 --classic 或者 --universal
sencha app init --ext=/path/to/extjs/ AppName --modern

执行构建后,应用程序可以在任意Web服务器上部署: sencha app build  

app install子命令

确保不完整的Sencha Cmd应用程序变得可以运行(补充缺失的文件),示例:

Shell
1
2
3
sencha app install --frameworks=/path/to/extjs
# frameworks是 6.1引入的特性,允许你指向一个具有多个版本ExtJS的目录
# 当前使用的ExtJS版本定义在workspace.json中,Cmd会自动选择最匹配的版本

workspace init子命令

确保当前目录是Sencha Cmd工作区或者工作区的一部分

workspace install子命令

确保不完整的Sencha Cmd工作区变得可以运行(补充缺失的文件),示例:

Shell
1
sencha workspace install --frameworks=/path/to/extjs 

workspace cleanup子命令

从workspace.json中移除已经不存在于工作区的应用程序条目

6.5

ES6支持

Cmd 6.5的主要变化就是支持ES6,即使是ExtJS 4.1.1+、Touch 2.1.x+也可以使用ES6来编写代码了

Cmd能够把ES6代码编译(Transpile)为老版本的JavaScript,这样老的浏览器可以被很好的支持。由于Transpile处理本身的特性,它必须在产品构建时执行,因此,你必须使用支持ES6的现代浏览器才能使用开发者模式(Developer Mode)

产品构建支持的浏览器包括IE8+和其它主流浏览器

如果你对那些老浏览器没兴趣,可以禁止Transpile:

app.json
JavaScript
1
2
3
4
5
"output": {
    "js": {
        "version": "ES6"
    }
}
← OpenTSDB学习笔记
ECMAScript6学习笔记 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • ExtJS 4的组件机制
  • ExtJS 4的事件系统
  • ExtJS知识集锦
  • ExtJS 4常用组件之表格
  • 定制ExtJS 4主题

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2