WeexでTypeScript （未解決）

WeexはTypeScriptをデフォルトでサポートしていない。

↓こちらには、Weex界でやたらと見かけるトトロのアイコンの中の人(？)のgithubにTypeScriptのサンプルを置いてある。
しかし、iOSとかで動かないし、ビルドしても.jsしかできないしやめました。
誰か使い方のアドベントカレンダー書いててくださいw

https://github.com/Hanks10100/weex-typescript-example

※今後便宜上「トトロの人」と呼びます

# プロジェクト作成

TypeScriptの略で`ts`の`ts-sample`のプロジェクト名つけますね。

```bash
weex create ts-sample
```

とりあえずこのように選びました。好みですね。
あとで参考にするサイトが`yarn`なのでそれ使うのが無難です。

```bash
? Project name ts-sample
? Project description A weex project
? Author shinriyo <shinriyo@gmail.com>
? Select weex web render latest
? Babel compiler (https://babeljs.io/docs/plugins/#stage-x-experimental-presets) stage-0
? Use vue-router to manage your view router? (not recommended) No
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes # <=== ここまではEnterを連打でOK.
? Should we run `npm install` for you after the project has been created? (recommended) yarn  # <=== ここだけyarnが無難だ！
```

# npmのパッケージをインストール

`npm`か`yarn`での質問で`yarn`を選んだので、今回はずっと`yarn`を使用します。

```bash
cd ts-sample/
yarn
```

以下の警告が出てきました。が無視。

```bash
warning ../../../package.json: No license field
```

僕はこの`yarn`のバージョンを使ってます。

```bash
yarn --version                                                                                                                    1454ms  Sun Dec  2 14:04:23 2018
1.5.1
```

後からエラーがでた時の切り分けのため一旦今の状態で起動の確認しておきましょう。
これでビルドから起動とブラウザで勝手に開くまでできます。

```bash
yarn serve
```

<img width="717" alt="Screen Shot 2018-12-02 at 14.06.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/83223841-d44f-4df7-7617-fadf2aaac44f.png">

## とりあえず

今のうちにgit管理しましょう。（hgでもいいけど）

トトロの人が.gitignore置いてあるのでそれ使うのがいいと思います。
`https://raw.githubusercontent.com/apache/incubator-weex/master/.gitignore`
この.gitignoreをパクって直下に配置して以下実行する！

```git
git init
git add .
git commit -m 'first commit'
```

# 開始

これを参考にします。中国語です。コマンドだけ読めるのでパクります。

https://www.jianshu.com/p/17ab49624933

```bash
yarn add webpack typescript vue vue-class-component weex-loader ts-loader -D
```

直下に以下のものをセット

```js:./tsconfig.json
{
    "compilerOptions": {
        "target": "es5",
        "lib": [
            "dom",
            "es5",
            "es2015"
        ],
        "module": "es2015",
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "removeComments": true,
        "suppressImplicitAnyIndexErrors": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "allowJs": true
    },
    "include": [
        "./src/**/*"
    ]
}
```

`tsconfig.json`に以下に置き換えます。（元のコードは消します。もうgit管理下なので思い切ってやりましょう、ミスっても`git checkout tsconfig.json`）

```ts:./tsconfig.json
const path = require('path');
const webpack = require('webpack');

var distDir = path.join(__dirname, 'dist');
var pageDir = path.join(__dirname, 'src', 'page')

module.exports = {
    entry: {
        example: [path.join(pageDir, 'example', 'index.ts')]
    },
    output: {
        path: distDir,
        filename: '[name].js'
    },
    resolve: {
        extensions: ['.ts', '.js', '.vue']
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: 'ts-loader',
                exclude: /node_modules/,
                options: {
                    appendTsSuffixTo: [/\.vue$/]
                }
            },
            {
                test: /\.vue$/,
                loader: 'weex-loader'
            }
        ]
    },
    externals: {
        vue: 'Vue'
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: '// { "framework": "Vue" } \n',
            raw: true,
            exclude: 'Vue'
        })
    ],
    mode: 'development'
}
```

元の記事には`mode: 'development'`がないですが、以下の警告が出るので追記しましたよ。

```
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
```

`mkdir src/types/`でフォルダ作っておいて。

### TypeScriptのコードセクションに.vueファイルをインポートさせる。

```ts:./src/types/vue.d.ts
declare module "*.vue" {
    import Vue from 'vue'
    export default Vue
}
```

## weexインスタンスオブジェクトを宣言し、他のモジュールを自分で拡張することができます

```ts:./src/types/weex.d.ts
declare namespace we {
    interface instance {
        /** この変数には、現在のWeexページのすべての環境情報が含まれます。 */
        config: any

        /** ネイティブモジュールに関連するメソッド */
        requireModule(name: string): any
    }
}

declare var weex: we.instance
```

`./package.json`を開き
元々あった`"dev": "webpack --env.NODE_ENV=common --progress --watch",`は消します。
`"dev": "webpack --config ./webpack.config.js -w"`にします。

`--watch`と`-w`は同じと思う。`./webpack.config.js`に丸投げするように変えたんだと思うけど・・。
最後の`,`忘れないように気をつけてね。（僕は忘れたw）

```json:./package.json
  "scripts": {
    "start": "npm run serve",
    "build": "webpack --env.NODE_ENV=common",
    "build:prod": "webpack --env.NODE_ENV=production",
    "build:prod:web": "webpack --env.NODE_ENV=release",
    "build:plugin": "webpack --env.NODE_ENV=plugin",
    "clean:web": "rimraf ./release/web",
    "clean:ios": "rimraf ./release/ios",
    "clean:android": "rimraf ./release/android",
    "dev": "webpack --config ./webpack.config.js -w",
    "unit": "karma start test/unit/karma.conf.js --single-run",
    "test": "npm run unit",
```

# 動かすぜ

まずこのフォルダ作りましょう。

```bash
mkdir src/page/
mkdir src/page/example/
```

`example`は今回`webpack.config.js`に記載したものなので、
もし、exampleって名前が嫌なら、`webpack.config.js`も一緒に変えないといけませんよ。

* Vueファイル

```vue:./src/page/example/example.vue
<template>
    <div><text>hello {{info}}</text></div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component
export default class Example extends Vue {
  info = "weex";
}
</script>
```

* さっきのvueファイルをインポーとしているtsファイル

```ts:./src/page/example/index.ts
import Example from './example.vue'
new Example({ el: '#root' })
```

# ビルド

```
yarn dev 
```

この際以下のような警告`Do you want to install 'webpack-cli' (yes/no): `ってでたら`yes`をタイプして実行して`webpack-cli`入れましょうね。

```bash
2814ms  Sun Dec  2 14:25:53 2018
yarn run v1.5.1
warning ../../../package.json: No license field
$ webpack --config ./webpack.config.js -w
One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
 - webpack-cli (https://github.com/webpack/webpack-cli)
   The original webpack full-featured CLI.
We will use "yarn" to install the CLI via "yarn add -D".
Do you want to install 'webpack-cli' (yes/no): yes
Installing 'webpack-cli' (running 'yarn add -D webpack-cli')...
```

# 実行

これをどうやって画面に出すのかな？
普段の`yarn start`でいいのかしら？

僕の環境だとWebpack4のせい？で以下のエラーがでました。

```
yarn start                                                                                                                  14.8s  Sun Dec  2 15:24:51 2018
yarn run v1.5.1
warning ../../../package.json: No license field
$ npm run serve

> ts-sample@1.0.0 serve /Users/shinriyo/development/weex_apps/ts-sample
> webpack-dev-server --env.NODE_ENV=development --progress

module.js:545
    throw err;
    ^

Error: Cannot find module 'webpack/bin/config-yargs'
    at Function.Module._resolveFilename (module.js:543:15)
    at Function.Module._load (module.js:470:25)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/shinriyo/development/weex_apps/ts-sample/node_modules/webpack-dev-server/bin/webpack-dev-server.js:54:1)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
```

## package.json

`yarn add webpack-dev-server -D`みたいな感じで以下のものたちが怪しいので入れておきました。
数rと

```json:package.json
    "webpack": "4.19.1",
    "webpack-bundle-analyzer": "^2.13.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10",
    "webpack-merge": "^4.1.2",
    "webpack-uglify-parallel": "^0.1.4",
    "weex-loader": "^0.7.12",
    "weex-vue-precompiler": "^0.1.17"
```

依存関係がよくわからないので載せておきます。

```json:package.json
{
  "name": "ts-sample",
  "version": "1.0.0",
  "description": "A weex project",
  "author": "",
  "private": true,
  "scripts": {
    "start": "npm run serve",
    "build": "webpack --env.NODE_ENV=common",
    "build:prod": "webpack --env.NODE_ENV=production",
    "build:prod:web": "webpack --env.NODE_ENV=release",
    "build:plugin": "webpack --env.NODE_ENV=plugin",
    "clean:web": "rimraf ./release/web",
    "clean:ios": "rimraf ./release/ios",
    "clean:android": "rimraf ./release/android",
    "dev": "webpack --config ./webpack.config.js -w",
    "unit": "karma start test/unit/karma.conf.js --single-run",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src  test/unit --fix",
    "serve": "webpack-dev-server --env.NODE_ENV=development --progress",
    "ios": "weex run ios",
    "web": "npm run serve",
    "android": "weex run android",
    "pack:ios": "npm run clean:ios && weex build ios",
    "pack:android": "npm run clean:android && weex build android",
    "pack:web": "npm run clean:web && npm run build:prod:web"
  },
  "keywords": [
    "weex"
  ],
  "license": "MIT",
  "dependencies": {
    "phantom-limb": "0.0.1",
    "vue": "^2.5.17",
    "weex-vue-render": "^1.0.17"
  },
  "devDependencies": {
    "autoprefixer": "^8.0.0",
    "babel-core": "^6.26.0",
    "babel-eslint": "^8.2.1",
    "babel-loader": "^7.1.1",
    "babel-preset-stage-0": "^6.24.1",
    "chai": "^4.1.2",
    "css-loader": "^0.28.8",
    "eslint": "^4.15.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^3.0.1",
    "eslint-plugin-vue": "^4.0.0",
    "extract-text-webpack-plugin": "^3.0.2",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "fs-extra": "^5.0.0",
    "glob": "^7.1.2",
    "html-webpack-plugin": "^2.30.1",
    "html-webpack-plugin-for-multihtml": "^2.30.2",
    "ip": "^1.1.5",
    "karma": "^1.7.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-phantomjs-shim": "^1.5.0",
    "karma-sinon-chai": "^1.3.3",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "^2.0.6",
    "mocha": "^5.2.0",
    "node-notifier": "^5.1.2",
    "portfinder": "^1.0.13",
    "postcss-import": "^11.0.0",
    "postcss-loader": "^2.0.9",
    "postcss-plugin-weex": "^0.1.6",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.6.2",
    "script-ext-html-webpack-plugin": "^1.8.5",
    "sinon": "^4.1.3",
    "sinon-chai": "^2.14.0",
    "ts-loader": "^5.3.1",
    "typescript": "^3.2.1",
    "vue-class-component": "^6.3.2",
    "vue-loader": "^12.2.0",
    "vue-style-loader": "^3.0.3",
    "vue-template-compiler": "^2.5.11",
    "webpack": "4.19.1",
    "webpack-bundle-analyzer": "^2.13.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10",
    "webpack-merge": "^4.1.2",
    "webpack-uglify-parallel": "^0.1.4",
    "weex-loader": "^0.7.12",
    "weex-vue-precompiler": "^0.1.17"
  }
}
```

これはいらないかもしれない

```bash
rm -rf src/components
rm src/entry.js
rm src/index.vue
```

# URL

なぜかURLが勝手に立ち上がらない。
ここにアクセスしてみる。

http://localhost:8080/web/preview.html?page=example
すると、呼べて入るようだが、ブラウザのコンソール上で以下のエラーが発生する

これが謎。

```
Uncaught ReferenceError: Vue is not defined
    at eval (external_"Vue":1)
    at Object.vue (example.js:442)
    at __webpack_require__ (example.js:22)
    at eval (example.vue?./node_modules/weex-vue-loader/lib/script-loader.js!./node_modules/babel-loader/lib!./node_modules/ts-loader?{"appendTsSuffixTo":[{}]}!./node_modules/weex-vue-loader/lib/selector.js?type=script&index=0:9)
    at Object../node_modules/weex-vue-loader/lib/script-loader.js!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?{"appendTsSuffixTo":[{}]}!./node_modules/weex-vue-loader/lib/selector.js?type=script&index=0!./src/page/example/example.vue (example.js:386)
    at __webpack_require__ (example.js:22)
    at eval (example.vue:5)
    at Object../src/page/example/example.vue (example.js:408)
    at __webpack_require__ (example.js:22)
    at eval (index.ts:2)
```

`yarn add -D vue`でもダメ。

わかったら次回。