Ionic 3でtsconfig.jsonのpathsを使ってimportにaliasを当てようとしたらWebpackの設定でハマった

2018.11.15

困ったこと

Ionicを使ってスマホアプリ開発をしていて、アプリケーションの規模が大きくなるにつれて徐々にディレクトリ構造がカオスなことになってきた。リファクタリングしようと細かめにディレクトリを分けたら、今度は他のコンポーネントやサービスのimportimport { AnalyticsService } from '../../../../services/core/analytics.service';のようにひたすら../../が並ぶ状況になってしまった。tsconfig.jsonの変更で解決できるとの情報を見て試してみたのだが、これがまた全くうまくいかない。

環境

  • macOS Mojave 10.14(18A391)
  • iTerm
  • WebStorm
  • ndenv 0.4.0-4-ga339097
  • Node.js v7.1.0
  • Ionic 3.19.0

Ionicプロジェクトのディレクトリは以下のようになっている。(必要なもののみに絞ってある)



├── config.xml
├── ionic.config.json
├── package.json
├── platforms
├── plugins
├── resources
├── src
│   ├── app
│   ├── assets
│   ├── components
│   ├── constants
│   ├── directives
│   ├── index.html
│   ├── manifest.json
│   ├── models
│   ├── pages
│   ├── pipes
│   ├── service-worker.js
│   ├── services
│   └── theme
├── tsconfig.json
├── tslint.json
├── tslint.json.default
└── webpack.config.js

試すこと

定数を管理するファイルをsrc/constants/app.constant.tsに配置して運用している。この定数をimport { AppConstant } from '@constants/app.constant';で読み込めるようにしてみる。



export const AppConstant = {
  apiRoot: 'http://localhost:3000',
  // 本当はもうちょっといくつか設定がある
}

tsconfig.jsonを編集する

compilerOptionsのセクションに以下を追加した。カンマをつけるところ、つけないところに注意が必要。



"baseUrl": "src",
"paths": {
  "@constants/*": [ "constants/*" ]
}

変更後のtsconfig.jsonは以下の通り。



{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5",
    "baseUrl": "src",
    "paths": {
      "@constants/*": [ "constants/*" ]
    }
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "src/**/*.spec.ts",
    "src/**/__tests__/*.ts"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}

プロジェクトの直下にwebpack.config.jsを作成する

以下の内容でwebpack.config.jsを作成する。要はnode_modules/@ionic/app-scripts/config/webpack.configの設定をベースに自分の設定を追加している。



const path = require('path');
const webpackConfig = require('./node_modules/@ionic/app-scripts/config/webpack.config');

webpackConfig.dev.resolve.alias = {
  '@constants': path.join(__dirname, './src/constants')
};

作成したwebpack.config.jsを読み込むようにpackage.jsonに設定を加える

package.jsonの一番浅い階層にconfigセクションを追加して以下のような設定を追加する。



  "config": {
    "ionic_source_map_type": "source-map",
    "ionic_webpack": "./webpack.config.js"
  }

以下がpackage.jsonの全体像。だいぶ省略したので、このまま貼り付けても動かないことに注意。configセクションをどこに配置するかの参考として。



{
  "name": "myapp",
  "version": "0.0.1",
  "author": "Ionic Framework",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "scripts": {
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build",
    "lint": "ionic-app-scripts lint",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "dependencies": {
    "@angular/animations": "5.2.9",
    // その他いろいろ
  },
  "devDependencies": {
    "@ionic/app-scripts": "3.1.8",
    "typescript": "~2.6.2"
  },
  "description": "An Ionic project",
  "cordova": {
    "plugins": {
      "cordova-plugin-whitelist": {},
      // その他いろいろ
    },
    "platforms": [
      "ios"
    ]
  },
  "config": {
    "ionic_source_map_type": "source-map",
    "ionic_webpack": "./webpack.config.js"
  }
}

完成

これで無事import { AppConstant } from '@constants/app.constant';ができるようになった。これで多少のディレクトリの移動は全く問題なくなった!リファクタリングが捗る!??

メモ:どうやって解決に至ったか

  • 「ionic tsconfig path」「ionic tsconfig alias」等のキーワードで検索しまくって、出てきた以下の参考記事を全て読み、試してみた。
  • tsconfig.jsonの変更だけではうまくいかないとわかり、webpack.config.jsとの格闘開始。
  • webpack.config.jsのどこかにaliasというセクションがあり、そこにまずは自分の設定を入れてみないと記事の情報が正しいか間違っているかが判断できないと考えた。
  • webpack.config.jsは見たところJavaScriptなので、console.logで設定内容が見られるかと仮説を立ててみたら、案の定みることができた。
  • 記事の情報と見比べて、どこにaliasセクションを追加すればいいかあたりをつけてやってみたら、動いた。

だいぶ格闘方法が洗練されてきた。

参考記事