写给 iOS 程序员的 Weex 教程(4):构建自己的工作流,提高研发打包发布效率

2017/3/18 21:21 下午 posted in  iOS comments

Weex 和 iOS 是两套独立的编译环境,如何让这两者很好的配合,是提高我们开发效率的关键。

Webpack 配置

Webpack 是一个可以根据 js 文件之间引用关系把它们打包成一个文件的工具。weex 提供的 weex loader 则使 webpack 能将 we 文件编译成 jsbundle。我们用 weex init 命令初始化工程的时候已经默认生成了 webpack 的配置文件,开箱即用。只是默认的配置文件只能编译一个 we 文件,我们需要改造它支持同时编译多个 we 文件。
这里我们使用的 webpack 版本是 1.x 版。webpack.config.js 是 webpack 的配置文件。从后缀就能看出来,webpack 的配置文件其实是一个 js 模块。webpack 在加载它的时候会运行里面的代码,并获取到配置信息。
既然配置文件是可运行的,那理论上我们可以在里面干任何想干的事。正是利用这一点,我们可以 wepback 打包我们所需的所有 we 文件。
我们先来看下 webpack 如何配置:

require('webpack')
require('weex-loader')

var path = require('path')

module.exports = {
  entry: {
    main: path.join(__dirname, 'src', 'weex-bootstrap.we?entry=true')
  },
  output: {
    path: 'dist',
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.we(\?[^?]+)?$/,
        loaders: ['weex-loader']
      }
    ]
  }
}

配置信息是通过 module.exports 导出对象。配置对象的 entry 属性指定需要打包的入口 js 文件。entry 可以接受一个对象,里面的 value 是入口 js 文件。output 用来指定输出目录和文件名,上面代码里的 name 引用的是 entry 里的 key。moduleloaders 用来指定解析某些文件,这些 loader 是按顺序串形处理。loader 可以根据规则只处理某些文件。
了解了用法后我们就知道,只需要把所有要处理的 we 文件传到 entry 里就行,其他不用改。具体方法就是遍历指定目录,获取所有 we 文件,然后赋值给 entry

var path = require('path');
var fs = require('fs');

//get all we files
var sourcePath = path.join(__dirname, 'src');
var entries = {};
fs.readdirSync(sourcePath)
.forEach(function(file) {
  var filePath = path.join(sourcePath, file);
  var stat = fs.statSync(filePath);
  var extName = path.extname(filePath);
  var baseName = path.basename(filePath,extName);
  if (stat.isFile() && 
    extName === '.we') {
    var name = path.basename(file,extName);
    entries[name] = filePath + '?entry';
  }
});

module.exports = {
  entry: entries,
  output: {
    path: 'dist',
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.we(\?[^?]+)?$/,
        loaders: ['weex-loader']
      }
    ]
  }
}

这里的 pathfs 是 Node.js 提供的组件。 大家可能注意到文件名后面加了 ?entry 参数。它的用途是告诉 weex loader 当前 we 文件是一个入口文件,用来支持页面配置和页面数据
除了配置所需打包文件,我们还可以根据需要增加点小功能,比如正式发布版本我们想压缩 js 代码。Webpack 的 插件 UglifyJsPlugin 可以做到。更近一步,我们可以通过给 webpack 传参数做到只给正式版增加压缩功能。相关代码如下,就是这么简单:

var process = require('process');

var debug = true;
for (var i = 0; i < process.argv.length; i++) {
  if (process.argv[i] === '--release') {
    debug = false;
  }
}

if (!debug) {
  module.exports.plugins = [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ];
}

到此,算是配置完 webpack,现在开始改进 npm scripts。

npm scripts

npm scripts 是可定制的 npm 命令,用来运行一些常用操作。Weex 默认生成了 4 条,用途见备注:

  "scripts": {
    "build": "webpack", //打包
    "dev": "webpack --watch", //打包并监控文件变化,变化时再次打包
    "serve": "serve -p 8080", //启动一个小型 web 服务,端口是8080
    "test": "echo \"Error: no test specified\" && exit 1"
  }

这些命令太简单了,有一些不足:

  1. 没有清空打包结果的目录,打包结果可能会受上一次的影响;
  2. 每次开发需要手动运行好几个命令:打包监控(dev),启动 web 服务(serve) 和 启动 debugger 调试(weex debug);

针对这些问题,我们需要改进一下。
scripts 的命令都可以看作是在终端里运行的命令,所以我们可以利用终端的所有命令。改进结果如下:

  "scripts": {
    "build": "rm -Rf dist && webpack",
    "dev": "rm -Rf dist && webpack --watch",
    "serve": "serve -p 8080",
    "debug": "npm run dev & npm run serve & weex debug",
    "release": "rm -Rf dist && webpack --release",
    "test": "echo \"Error: no test specified\" && exit 1"
  }

我增加了一条 debug。这个用来开发调试时用。可以看到,都是终端里的命令用法。
对终端命令不熟悉的,我稍微解释一下:

  • rm 是删除命令;
  • && 表示前一条命令成功了就运行后一条;
  • & 表示前后两条命令同时进行。

npm scripts的用法就是在工程目录下,终端里运行: npm run {key}

引入 jsbundle 到 iOS 工程

通用以上两个配置,我们就能一条命令打包完。但如果想把它们作为资源文件一起打包进 iOS 工程里,则还需要把它们手动拖到 xcode 工程里。

只是如果每次打包完都需要手动拖入那会让人很崩溃的。这里我们就需要利用 xcode 的 “folder reference” 方式把 jsbundle 加入到工程里。“folder reference” 是指xcode 工程只保存对一个目录的引用。当编译的时候,会将这个目录下的所有文件都加入到工程里。同时这个目录下的文件结构也不会变,即如果存在子目录,也会保留它。

如果想让最终打包进应用里的目录名和现在的不一样,则需要有一个软链接中转。软链接类似 windows 下的快捷方式,是对一个文件 / 目录的引用。软链接的名字取我们想要的,然后拖这个软链接进入到工程里就行。
建立软链接的命令如下, 源目录在前,后面是软链接的名字:

ln -s ../dist main

Sublime Text 配置

如果你用的编辑器是 Sublime Text 的话,建议装之前提到的插件,并配置 project 文件。
默认的 cmd + t 快速打开命令会搜索当前打开目录下的所有文件,自然包括 node_modules 目录。这会产生大量干扰信息,肯定不是我们想要的。 project 配置文件能定义只包含某些文件夹,或者排除某些文件夹,很是方便:

{
    "folders":
    [
        {
            "path": ".",
            "folder_exclude_patterns": ["dist", "iOS", "node_modules"],
            "file_exclude_patterns": ["index.html", ".gitignore", "*.swp", "*.orig",".git",".gitmodules","npm-debug.log*"]
        }
    ]
}

以上就是我们现阶段的一些配置项,这些配置会让提高我们工作效率。当然建议大家可以根据自己的需要调整,以符合你们的需要。

下一篇将会如何做自己的增量更新