23、Ember.js 应用的打包、部署与 Grunt.js 构建工具使用指南

Ember.js 应用的打包、部署与 Grunt.js 构建工具使用指南

1. JavaScript 应用的目录结构规划

在开发 JavaScript 应用时,合理的目录结构规划至关重要。虽然 JavaScript 社区正在逐步形成标准的项目目录结构定义方式,但目前我们仍需遵循一些合理的准则。以 Ember.js 应用为例,可将资源分离到以下目录:
- js/app :项目中所有自行编写的 JavaScript 文件。
- js/lib :所有第三方 JavaScript 文件,部分文件可能已被压缩。
- js/test :项目中的所有 JavaScript 单元测试文件。
- css :项目的所有 CSS 文件直接存放在此文件夹。
- images :项目的所有图片文件。

需要注意的是,部分构建工具可能要求或偏好特定的目录结构。使用 Grunt.js 时,可告知其文件的位置,你也能自由使用自己的目录结构风格。这种目录结构便于应用、开发者和构建工具后续查找资源,多数目录为扁平结构,但 js/app 目录可能并非如此。

2. 自定义源代码的结构设计

拥有合理的源代码结构极为重要。在 Ember.js 应用开发中,若仅将所有 JavaScript 代码存于单个 app.js 文件,对于小型概念验证或示例应用而言高效便捷,但对于需要长期维护和部署到生产环境的应用,就需将源代码分离到不同文件。在设计源代码结构时,有两种方式可供选择:

2.1 按对象类型组织

js/app 目录下创建不同的子目录,将相同类型的对象(如控制器、视图等)集中存放。例如,有 controllers models routes views 等目录。在应用规模较小时,这种方式尚可管理,但从长远来看,维护难度较大。以 controllers 目录为例,难以快速区分各文件及其在应用中的职责,需查看文件内容才能确定。

2.2 按功能特性组织

将目录结构按照应用提供的功能特性进行划分。对于 Ember.js 应用,属于同一路由的代码存于同一文件夹,如 administration/accounts chart 等文件夹,其中包含该路由的路由、控制器和视图文件。这种以功能为中心的目录结构具有以下优点:
- 将逻辑分离到小且易于维护的文件中。
- 为每个文件在 js/app 目录中提供可预测的位置。
- 反映应用的主要功能,便于未来维护,也让新开发者更易理解。

3. js/test 目录的结构设计

建议将 js/test 目录按照 js/app 目录的结构进行组织,例如 js/test/administration/account js/test/administration/alerts 等目录。这样做能带来以下好处:
- 当测试失败时,可快速得知哪个功能特性的测试出现问题。
- 为测试文件在 js/test 目录中提供可预测的位置。
- 通过查看测试目录结构,可了解应用哪些部分测试较为完善,哪些部分需进一步关注。

4. 非 JavaScript 资产的组织

在完成 JavaScript 资产的结构设计后,还需对非 JavaScript 资产(如顶级目录内容和 Handlebars.js 模板)进行结构设计。

4.1 顶级目录的结构设计

顶级目录用于存放定义应用相关信息的文件,包括但不限于:
- index.html :定义应用的整体结构。
- 描述应用第三方依赖的文件。
- 告知构建工具如何组装和测试应用的构建文件。

4.2 模板的结构设计

建议将每个模板存于单独的文件,并使用自定义的 .hbs 扩展名(也可使用其他后缀,在组装应用时指定)。这些文件应根据应用的路由命名,能实现以下效果:
- 将每个模板分离到单独文件。
- 将相关模板分组到合理的目录结构中,与应用的功能特性相似。
- 通过目录名和文件名的组合,告知构建工具如何将模板编译为 JavaScript 代码,并自动命名模板。

以下是模板结构的 mermaid 流程图:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(templates):::process --> B(顶级路由模板文件):::process
    A --> C(administration 路由模板文件):::process
    A --> D(login 路由模板文件):::process
5. Ember.js 应用的组装过程

在将应用拆分为多个文件以方便开发和维护后,组装过程需将所有应用资产合并为单个文件。具体步骤如下:

5.1 源代码和模板的组装
  • JavaScript 文件
    1. 查找 js/app 目录下的每个文件。
    2. 对每个文件进行常见 JavaScript 错误检查(lint)。
    3. 与之前的文件进行拼接。
    4. 对拼接后的文件进行压缩。
  • 模板文件
    1. 查找每个 .hbs 文件。
    2. 将每个文件的内容赋值给 Ember.TEMPLATES[dirname/filename] = Ember.Handlebars.compile(fileContents)
    3. 与之前的模板进行拼接。
5.2 CSS 文件的组装
  • 查找每个 .css 文件。
  • 与之前的 CSS 文件进行拼接。
  • 对拼接后的内容进行压缩。

以下是 Ember.js 应用组装过程的 mermaid 流程图:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(JavaScript 文件):::process --> B(查找 js/app 目录下的文件):::process
    B --> C(进行 lint 检查):::process
    C --> D(拼接文件):::process
    D --> E(压缩文件到 app.js):::process

    F(模板文件):::process --> G(查找 *.hbs 文件):::process
    G --> H(编译到 Ember.TEMPLATES):::process
    H --> I(拼接模板到 app.js):::process

    J(CSS 文件):::process --> K(查找 *.css 文件):::process
    K --> L(拼接 CSS 文件):::process
    L --> M(压缩内容到 styles.css):::process

通过以上步骤,最终得到两个文件:一个 app.js 文件包含应用的所有自定义 JavaScript 代码,另一个 styles.css 文件包含应用的所有 CSS 代码。接下来,我们将探讨如何使用 Grunt.js 来构建和组装 Ember.js 应用。

6. 使用 Grunt.js 作为构建工具

Grunt.js 是一个 JavaScript 任务运行器,运行于 Node.js 环境中,主要用于自动化脚本压缩、代码检查、运行单元测试以及将应用资产合并为单个文件等任务。它基于管道概念构建,定义了应用的组装和测试流程。使用 Grunt.js 实现完整的应用组装管道包括以下步骤:
- 初始化 Grunt.js 构建系统。
- 将 JavaScript 文件合并为单个文件。
- 对合并后的文件进行代码检查。
- 将模板编译到合并后的文件中。
- 将合并后的文件压缩为可用于生产环境部署的文件。

Grunt.js 基于插件机制,要执行的任务由相应的插件完成。在组装 Montric 应用时,将按需安装所需插件。下面我们从初始化 Montric 的 Grunt.js 构建系统开始。

6.1 初始化 Montric 的 Grunt.js 构建

Grunt.js 期望在应用的顶级目录中找到两个文件:
- package.json :描述应用及其构建管道所需的依赖。
- Gruntfile.js :描述应用的组装方式。

首先,安装 Node 包管理器(NPM),可前往 http://nodejs.org 安装 Node.js,前往 http://npmjs.org 安装 NPM。

然后,添加 package.json 文件,初始内容如下:

{
  "name": "Montric",
  "version": "0.9.0",
  "devDependencies": {
    "grunt": "~0.4.1"
  }
}

该文件告知 Grunt.js 项目名称、当前版本以及组装项目所需的开发依赖。后续在构建 Montric 组装管道时,会在 devDependencies 部分添加更多依赖。

接着,添加 Gruntfile.js 文件,初始内容如下:

module.exports = function(grunt) {
  // 项目配置
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
  });
  // 默认任务
  grunt.registerTask('default', []);
};

此时,Gruntfile 尚未执行任何任务,但已包含足够信息以执行 grunt 命令。在测试 Gruntfile.js package.json 配置之前,需安装 Grunt.js 命令行界面(CLI),步骤如下:
1. 打开终端(Mac/Linux)或命令提示符(Windows)。
2. 输入以下命令:

npm install -g grunt-cli

NPM 会将 grunt-cli 安装到全局环境,使 grunt 命令可在系统的任何目录中执行。若首次构建已在 package.json 中指定依赖的应用,需先运行 npm install 安装这些依赖。

导航到项目目录,输入 grunt 命令,Grunt.js 将尝试使用之前创建的默认任务组装应用。

6.2 合并 JavaScript 代码

在完成应用构建管道的设置后,接下来安装 Grunt.js 的 concat 插件,通过以下命令实现:

npm install grunt-contrib-concat --save-dev

该命令会下载并安装最新版本的 grunt-contrib-concat 插件到项目目录, --save-dev 参数会将该插件版本信息添加到 package.json 文件中。安装后, package.json 文件内容如下:

{
  "name": "Montric",
  "version": "0.9.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0"
  }
}

为将所有 JavaScript 代码合并为单个文件,需扩展 Gruntfile.js 文件,代码如下:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: '\n'
      },
      dist: {
        src: ['js/app/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.registerTask('default', ['concat']);
};

Gruntfile.js 中添加了 concat 对象,其中 options 对象指定在拼接 JavaScript 文件时在每个文件间添加换行符, dist 对象定义了插件查找要拼接的 JavaScript 文件的位置以及拼接结果的输出文件。 src 属性指定查找 js/app 目录下的所有 .js 文件, dest 属性指定将拼接结果输出到 dist 目录下以项目名称命名的文件(如 Montric.js )。

通过以上步骤,我们完成了使用 Grunt.js 合并 JavaScript 代码的操作。后续还将继续探讨如何对合并后的文件进行代码检查、模板编译和文件压缩等操作,以实现完整的 Ember.js 应用组装和部署。

Ember.js 应用的打包、部署与 Grunt.js 构建工具使用指南

7. 对合并后的 JavaScript 文件进行代码检查

在将 JavaScript 文件合并为单个文件后,需要对其进行代码检查(lint),以确保代码的质量和一致性。Grunt.js 提供了 grunt-contrib-jshint 插件来完成这项任务。

首先,安装 grunt-contrib-jshint 插件,在终端中执行以下命令:

npm install grunt-contrib-jshint --save-dev

该命令会下载并安装最新版本的 grunt-contrib-jshint 插件到项目目录,并将其版本信息添加到 package.json 文件中。安装后, package.json 文件会更新为如下内容:

{
  "name": "Montric",
  "version": "0.9.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-jshint": "~2.1.0"
  }
}

然后,扩展 Gruntfile.js 文件以配置 jshint 任务,代码如下:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: '\n'
      },
      dist: {
        src: ['js/app/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    jshint: {
      all: ['dist/<%= pkg.name %>.js']
    }
  });
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.registerTask('default', ['concat', 'jshint']);
};

在上述代码中, jshint 对象定义了要检查的文件, all 属性指定对合并后的 dist/Montric.js 文件进行代码检查。通过 grunt.loadNpmTasks 加载 grunt-contrib-jshint 插件,并将 jshint 任务添加到默认任务列表中。

以下是执行代码检查步骤的表格总结:
| 步骤 | 操作 | 命令 |
| ---- | ---- | ---- |
| 1 | 安装插件 | npm install grunt-contrib-jshint --save-dev |
| 2 | 配置 Gruntfile.js | 在 Gruntfile.js 中添加 jshint 任务配置 |
| 3 | 执行任务 | 运行 grunt 命令 |

8. 模板编译到合并后的文件中

Ember.js 应用使用 Handlebars.js 模板,需要将这些模板编译到合并后的 JavaScript 文件中。Grunt.js 提供了 grunt-ember-templates 插件来完成模板编译任务。

安装 grunt-ember-templates 插件,在终端中执行以下命令:

npm install grunt-ember-templates --save-dev

安装后, package.json 文件会更新为如下内容:

{
  "name": "Montric",
  "version": "0.9.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-jshint": "~2.1.0",
    "grunt-ember-templates": "~1.2.0"
  }
}

扩展 Gruntfile.js 文件以配置模板编译任务,代码如下:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: '\n'
      },
      dist: {
        src: ['js/app/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    jshint: {
      all: ['dist/<%= pkg.name %>.js']
    },
    ember_templates: {
      options: {
        templateBasePath: 'templates/'
      },
      dist: {
        src: ['templates/**/*.hbs'],
        dest: 'dist/<%= pkg.name %>_templates.js'
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-ember-templates');
  grunt.registerTask('default', ['concat', 'jshint', 'ember_templates']);
};

在上述代码中, ember_templates 对象配置了模板编译任务。 options 中的 templateBasePath 指定模板文件的基础路径, dist 对象定义了要编译的模板文件路径和输出文件路径。

以下是模板编译步骤的 mermaid 流程图:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(模板文件):::process --> B(查找 templates 目录下的 *.hbs 文件):::process
    B --> C(编译模板):::process
    C --> D(输出到 dist/Montric_templates.js):::process
9. 文件压缩

为了减少应用在网络传输中的数据量,需要对合并后的 JavaScript 文件和 CSS 文件进行压缩。Grunt.js 提供了 grunt-contrib-uglify 插件用于压缩 JavaScript 文件, grunt-contrib-cssmin 插件用于压缩 CSS 文件。

首先,安装这两个插件,在终端中执行以下命令:

npm install grunt-contrib-uglify grunt-contrib-cssmin --save-dev

安装后, package.json 文件会更新为如下内容:

{
  "name": "Montric",
  "version": "0.9.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-jshint": "~2.1.0",
    "grunt-ember-templates": "~1.2.0",
    "grunt-contrib-uglify": "~5.2.1",
    "grunt-contrib-cssmin": "~4.0.0"
  }
}

扩展 Gruntfile.js 文件以配置文件压缩任务,代码如下:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: '\n'
      },
      dist: {
        src: ['js/app/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    jshint: {
      all: ['dist/<%= pkg.name %>.js']
    },
    ember_templates: {
      options: {
        templateBasePath: 'templates/'
      },
      dist: {
        src: ['templates/**/*.hbs'],
        dest: 'dist/<%= pkg.name %>_templates.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      dist: {
        files: {
          'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.js', 'dist/<%= pkg.name %>_templates.js']
        }
      }
    },
    cssmin: {
      target: {
        files: {
          'dist/styles.min.css': ['css/*.css']
        }
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-ember-templates');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.registerTask('default', ['concat', 'jshint', 'ember_templates', 'uglify', 'cssmin']);
};

在上述代码中, uglify 对象配置了 JavaScript 文件的压缩任务, options 中的 banner 用于在压缩文件开头添加注释信息, dist 对象指定要压缩的文件和输出文件。 cssmin 对象配置了 CSS 文件的压缩任务,指定要压缩的 CSS 文件和输出文件。

以下是文件压缩步骤的表格总结:
| 步骤 | 操作 | 命令 |
| ---- | ---- | ---- |
| 1 | 安装插件 | npm install grunt-contrib-uglify grunt-contrib-cssmin --save-dev |
| 2 | 配置 Gruntfile.js | 在 Gruntfile.js 中添加 uglify cssmin 任务配置 |
| 3 | 执行任务 | 运行 grunt 命令 |

10. 总结与注意事项

通过以上步骤,我们完成了 Ember.js 应用的打包、部署和使用 Grunt.js 进行构建的整个流程。从合理规划目录结构,到使用 Grunt.js 进行文件合并、代码检查、模板编译和文件压缩,最终实现了一个可用于生产环境部署的 Ember.js 应用。

在使用 Grunt.js 时,需要注意以下几点:
- 确保 Node.js 和 NPM 已正确安装,并且版本兼容。
- 安装插件时,使用 --save-dev 参数将插件版本信息添加到 package.json 文件中,方便团队协作和项目维护。
- 在配置 Gruntfile.js 时,仔细检查每个任务的配置参数,确保任务按预期执行。

以下是整个 Ember.js 应用组装和部署流程的 mermaid 流程图:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(初始化 Grunt.js):::process --> B(合并 JavaScript 文件):::process
    B --> C(代码检查):::process
    C --> D(模板编译):::process
    D --> E(JavaScript 文件压缩):::process
    E --> F(CSS 文件压缩):::process
    F --> G(完成部署):::process

通过遵循这些步骤和注意事项,你可以高效地开发、打包和部署 Ember.js 应用,提高开发效率和应用性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值