App Build Scripts
http://ionicframework.com/docs/v2/resources/app-scripts/
Ionic使用了TypeScript和Sass代码。这些代码需要转换为对浏览器友好的代码,所以需要一个build过程。@ionic/app-scripts是一个创建简单的或可以高度自定义的build过程的配置方式。
它是如何工作的?
Ionic应用使用ionic serve和ionic run命令来开发。这两个命令需要把代码进行编译,组合到一个文件里。
当ionic serve或ionic run被调用的时候,实际上是调用了NPM Script,这些脚本调用了@ionic/app-scripts来执行这些build过程。
为什么使用App Script?
大多数应用使用相似的build进程。我们觉得让用户把时间花在build过程中更好,而不是花在给自己的App拼凑build脚本上。我们认为大多数用户都需要这样的build过程。
那Gulp呢?
之前Ionic曾经使用gulp作为build工具。但是过去几年来,gulp的开发越来越少,并且被否决的警告越来越多。为了充分利用标准并且免费的NPM Script,我们减少了对gulp的依赖并且简化了开发体验。
注意,开发者如果想继续使用gulp的话也是可以的。我们认为NPM Script是一种更好的方式,但并不禁止继续使用gulp。
提供了什么脚本?
@ionic/app-scripts提供了以下脚本:
- build:
build调用@ionic/app-scripts来编译TypeScript,sass,打包JavaScript文件等等。 - bundle:
bundle使用Rollup.js来把很多小的JavaScript文件打包成一个单独的高性能的JavaScript文件。 - clean:
clean将会删除所有build过程产生的文件,一般是删除www目录下的文件。 - cleancss:
cleancss使用CleanCSS来压缩css文件,可以让css文件体积更小,加载更快。 - closure:
closure使用Google’s Closure Compiler来压缩JavaScript文件,减小体积提高加载速度。 - copy:
copy从www目录里拷贝文件。 - lint:
lint对TypeScript源码运行TSLint。需要在项目根目录下存在tslint.json文件。 - minify:
minify对JavaScript(如果uglify或closure可用的话)和css(cleancss)运行压缩任务。 - ngc:
ngc调用Angular Ahead-of-time compiler来创建高性能的应用,即以AoT模式编译。 - sass:
sass遍历应用目录寻找scss文件并且将它们打包到一个css文件里。 - template:
template用来把Angular模板转换成inline-templates,使应用载入更快。 - transpile:
transpile把TypeScript转换成JavaScript代码。 - tsc:
tsc调用TypeScript编译器。 - uglifyjs:
uglifyjs用来把JavaScript最小化,运行更快。 - watch:
watch创建一个很小的快速的build进程,用于开发过程中。
提供自定义配置
@ionic/app-scripts提供的默认配置覆盖了大多数开发场景。然而如果开发者需要自定义build进程运行的配置,可以这样做。
最简单的配置@ionic/app-scripts的方式是使用package.json文件中的config选项。
在package.json文件中添加一个config入口。开发者可以提供他们自己的配置文件,比如minification(closure编译,uglify2),和bundling(rollup)。
看下面这个明确的自定义文件的例子:
"config": {
...
"ionic_rollup": "./config/rollup.config.js",
"ionic_cleancss": "./config/cleancss.config.js",
...
},
上面这个例子里,从配置文件路径提供了rollup和cleancss的自定义配置。
下面的config值用来映射到任务的配置文件:
| Config File | NPM Config Property |
|---|---|
| CleanCss | ionic_cleancss |
| Closure Compiler | ionic_closure |
| Copy | ionic_copy |
| NGC | ionic_ngc |
| Rollup | ionic_rollup |
| Sass | ionic_sass |
| TSLint | ionic_tslint |
| UglifyJS | ionic_uglifyjs |
默认配置是学习如何自定义选项的好例子。
Command line flags也能够用来提供自定义配置。
自定义项目结构
在大多数情况下,Ionic提供的默认项目结构可以很好的工作。然而如果开发者要修改项目结构来适应具体的场景,也可以这样做。
像上面提到的一样,通过package.json中的config选项,开发者可以指定他们的自定义项目结构。
| Config Values | NPM Config Property | Defaults |
|---|---|---|
| root directory | ionic_root_dir |
process.cwd() |
| tmp directory | ionic_tmp_dir |
.tmp |
| src directory | ionic_src_dir |
src |
| www directory | ionic_www_dir |
www |
| build directory | ionic_build_dir |
build |
Ionic环境变量
IONIC_ENV这个环境变量用于决定build过程是使用development模式还是production模式。这个变量可以这样访问:
if (process.env.IONIC_ENV === 'prod') {
console.log('we got a production buildp');
} else {
console.log('we got a development build');
}
任务细节
Bundle
Ionic使用Rollup根据来把不同的JavaScript文件合并成一个文件。这个过程一般叫做打包。
第三方Module导出的错误
当在代码中使用第三方库的时候,有时Rollup需要这个库相关的信息。大多数情况下会工作正常。极少的情况下有些库不知道如何导出数据,我们需要告诉Rollup什么该被导出。这个过程被称作named Export。
如果遇到了类似下面的错误信息:
bundle failed: Module myApp/node_modules/js-extend/extend.js does not export extend (imported by myApp/node_modules/pouchdb/lib/index-browser.es.js)
最好的办法是根据上面的步骤创建一个自定义的Rollup配置文件。需要打开package.json文件,如果config节点不存在的话,创建一个config节点,添加ionic_rollup值:
"config": {
"ionic_rollup": "./scripts/rollup.config.js"
}
自定义的rollup配置文件会放置在Ionic应用根目录下的scripts目录里。这个例子里这个文件名为rollup.config.js。
填写Rollup配置最简单的方式是修改一个已存在的Rollup配置文件。打开node_modules/@ionic/app-scripts/config/rollup.config.js文件复制并粘贴其中的代码到scripts/rollup.config.js中。
现在配置文件的格式正确了,继续来修复上面的错误。在这个例子里,我们试图安装一个超级酷的库pouchdb。从错误信息可以看出,pouchdb的lib/index-browser.es.js文件试图从js-extend库引入extend,但报错了。
这个错误意味着Rollup不知道js-extend导出了任何名为extend的东西。解决方案是我们需要告诉Rollup,js-extend确实导出了extend。
这是Rollup默认的设置:
plugins: [
builtins(),
commonjs(),
nodeResolve({
...
}),
globals(),
json()
]
在Rollup配置里,我们要找到commonjs插件,添加一个namedExports的入口。
commonjs({
namedExports: {
// pouchdb
'node_modules/js-extend/extend.js': ['extend']
}),
我们继续分析namedExport。
我们的错误看起来是这样的:
bundle failed: Module myApp/node_modules/js-extend/extend.js does not export extend (imported by myApp/node_modules/pouchdb/lib/index-browser.es.js)
错误信息提到了myApp/node_modules/js-extend/extend.js,还提到了一个名为extend的导出。
在namedExport入口,我们不再使用myApp,但是包含其他的路径作为入口的键。入口的值是一个string的数组,这个例子里只有一个extend的入口。
提供namedExports能够解决大多数的第三方库的问题。
严格模式
Ionic应用(或任何使用现代JavaScript的应用)默认采用strict mode。大多数情况下开发者不需要关心这些。如果一个第三方库没有采用strict mode支持,在Rollup配置里禁止strict mode可以解决。一个流行的库Firebase需要把strictMode设置为false。
使用脚本标签包含
如果还有其他的错误导致无法打包,那就将脚本用<script>标签引入进来。这是过去二十年来一直使用的方式,现在也可以继续使用。
为了在Ionic的Page或Component中使用一个库,给其一个声明并创建一个变量。例如jQuery的例子:
declare const jQuery:any;
当jQuery被浏览器载入的时候,可以通过window.jQuery来使用它。在上面的例子里,我们把jQuery映射到了window.jQuery对象。这样jQuery就可以无需其他工作就能在TypeScript中使用了。