LoginSignup
1
0

More than 3 years have passed since last update.

expressをESモジュールに変更する手順(babel利用)

Last updated at Posted at 2021-01-09

目的

バックエンドをESモジュールで記載できるようにしたい(フロントエンドに合わせる)という目的です。

結果

  • ESMとしてexportしたモジュールはimportする、module.exportの場合(node)はrequire()を利用するということに気を付ければ、混在していても問題なく動く。

実現手段

  • expessをES6(import)で利用できるようにするため、babelでトランスパイルする。
    ⇒package.json に 「type: module」を追加すればESモジュールを使えますが、jsファイルの拡張子(.cjs、.mjs)の切り分けが面倒なのでbabelにします。

  • express-generatorでひな形を生成する。

  • 開発時は「babel-node」で実行(ビルド不要)可能とする。トランスパイルしたjsファイルが必要な場合はbuildを行う。

  • sequelizeと組み合わせて使用する(sequelizeはnodeモジュール形式で生成される。ES6形式で記載したexpress側で問題なく利用できることを確認する)

前提

  • nodeとyarnがインストール済みであること (npmを使う場合は適宜読み替えてください)

利用モジュール

{
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "morgan": "~1.9.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.12.10",
    "@babel/core": "^7.12.10",
    "@babel/node": "^7.12.10",
    "@babel/preset-env": "^7.12.11"
  }
}

手順

①expressのひな形をESモジュールに変更し、babelでコンパイルする

1. express-generatorでひな形を作成(viewは生成しない。.gitignoreは生成する)

npx express-generator express-generator-babel --no-view --git

2. (作成されたフォルダに移動し)必要なライブラリをインストール

yarn install

3. expressが起動することを確認

yarn start

B397.tmp.png

ブラウザで「http://localhost:3000」 を表示する
515.tmp.png

4. babelインストール

yarn add @babel/cli  @babel/core @babel/preset-env -D

5. babelの設定ファイル(.babelrc)を作成する

targetにcurrentを入れることで、インストールされているnode.jsが理解できる形でトランスパイルされます。
(最近のnodeであればawaitやasyncなどがヘルパー関数ではなく、そのまま出力されます(pollyfill不要))

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "node": "current"
                }
            }
        ]
    ]
}

6. babelでビルドするため、フォルダ構成を変更する。

  • jsファイルを「/src」フォルダ配下にすべて移動する
mkdir src
mv  bin/ routes/ app.js src/

※「bin」「routes」フォルダと、app.jsファイルを「src」フォルダに移動している。

変更前後.png

  • フォルダ階層が変わったためソースを一部修正する

app.js (publicフォルダの位置を修正)

app.use(express.static(path.join(__dirname, 'public')));
 ↓
app.use(express.static(path.join(__dirname, '../public')));
  • トランスパイル先フォルダを作成する
mkdir dist

7. ビルド用コマンドをpackage.jsonに追加する

package.json の "scripts"に下記コマンドを追加する。

"build": "babel src --out-dir dist --copy-files && babel ./src/bin/www --out-file ./dist/bin/www"

※.src/bin/www は拡張子がないjsファイル。フォルダ指定では対象にならないため、個別にトランスパイルをしている。

8. babelでトランスパイルを行う

yarn build

9. トランスパイルしたソースで動作確認を行う

  • package.json の "scripts"に下記コマンドを追加する。
"serve": "node ./dist/bin/www"
  • サーバを起動する
yarn serve

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。
515.tmp.png

10. ESモジュールに変更して動作確認を行う

  • require()をimportに変更しても動作することを確認する。
  1. module.exportsからES6のexportに変更した場合、読み込み元も「import」に修正する必要がある。
  2. ソース内でrequire()をimportに変更しても、外部にエクスポートする「module.export」を変更しなければ、呼び出し元は変更不要。

/src/routes/index.js

// var express = require('express');  //コメントアウト
import express from 'express';        //追加
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
});

// module.exports = router;  //コメントアウト
export default router;       //追加

/src/app.js

// var express = require('express');  //コメントアウト
// var path = require('path');
// var cookieParser = require('cookie-parser');
// var logger = require('morgan');

import express from 'express';        //追加
import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';

// var indexRouter = require('./routes/index');  //コメントアウト
import indexRouter from './routes/index';        //追加
var usersRouter = require('./routes/users');

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

module.exports = app;  //コメントアウトしない。読み込み元(bin/www)を変更せず、require()のままとするため。
//export default app;  // exportに書き換えると、読み込み元をimportに書き換える必要がある。

11. ESモジュール化後の動作確認

yarn build
yarn serve
  • ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

12. 開発用に「babel-node」を導入する(ビルド無しで動作させるため)

  • babel-nodeをインストールする
yarn add @babel/node -D
  • package.jsonの startを修正する
"start": "node ./bin/www",
 ↓
"start": "babel-node ./src/bin/www",
  • babel-nodeで起動することを確認する(build不要)
yarn start

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

②sequelize+sqliteを追加してデータを取得する

sequelize-cliを利用して生成したひな形(node module形式)を、express側から利用できることを確認する。

13. sequelize導入(DBはsqliteを利用する。別にサーバを作る必要がないため)

yarn add sequelize sqlite3
yarn add sequelize-cli -D
  • 初期化時に自動生成されるフォルダを「/src」配下にするため、先に「.sequelizerc」ファイルを作成する(プロジェクトルート)
touch .sequelizerc
  • sequelize関連ファイルを「/src/seqelize」で管理するように設定する(指定しない場合は、プロジェクトルートに作成される)

const path = require('path');

module.exports = {
    'config': path.resolve('./src/sequelize/config', 'config.json'),
    'models-path': path.resolve('./src/sequelize/models'),
    'seeders-path': path.resolve('./src/sequelize/seeders'),
    'migrations-path': path.resolve('./src/sequelize/migrations'),
};
  • マイグレーションのための初期化を行う
yarn sequelize init

※コマンドは、sequelize, sequelize-cli どちらでもよい(エイリアス)

プロジェクトルートではなく、/src/sequelizeに作成されます。
sequelize-init.png

  • config.jsonをsqlite用に書き換える。
{
  "development": {
    "database": "database_development",
    "dialect": "sqlite",
    "storage":"db/proto_app_dev.sqlite"
  },
  "test": {
    "database": "database_test",
    "dialect": "sqlite",
    "storage":"db/proto_app_test.sqlite"
  },
  "production": {
    "database": "database_production",
    "dialect": "sqlite",
    "storage":"db/proto_app.sqlite"
  }
}

14. sequelize-cli でテーブル定義のひな形を作成後、マイグレーションを行う

  • sequelize model:generateでmodel定義と、マイグレーション用のひな形を生成する。
yarn sequelize model:generate --name User --attributes name:string,birth:date,email:string

migrationsにひな形が生成されます。
sequelize-generate.png

  • マイグレーションを行い、テーブルを作成する
yarn sequelize db:migrate

db-migrate.png

15. テスト用データを登録(db:seed)する

  • ひな形を作成する
yarn sequelize seed:generate --name user
  • ひな形を修正(登録データを用意する)
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    const now = new Date();
    const birth = new Date(now);
    const seeds = []; 
    const subtractYear = ( date, year ) => new Date( date.setYear(date.getFullYear() - year) );

    seeds.push({ name:"name1", birth:subtractYear(birth, 1), email:"mail1@example.com", createdAt: now, updatedAt: now });
    seeds.push({ name:"name2", birth:subtractYear(birth, 1), email:"mail2@example.com", createdAt: now, updatedAt: now });
    seeds.push({ name:"name3", birth:subtractYear(birth, 1), email:"mail3@example.com", createdAt: now, updatedAt: now });
    return await queryInterface.bulkInsert("users",seeds, {});
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.bulkDelete('users', null, {});
  }
};
  • seedを登録する
 yarn sequelize  db:seed:all

※やり直す場合は「yarn sequelize db:seed:undo:all」

16. 作成したmodelをexpress側から利用し、登録したデータが取得できることを確認する

  • ./route/users.jsを修正し、sequelizeのmodel(users)を全レコードjson形式で返すように修正する

修正前

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
    res.send('respond with a resource');
});

module.exports = router;

修正後

import db from "../sequelize/models/index";
import express from 'express';
const router = express.Router();

/* GET users listing. */
router.get('/', async function(req, res, next) {
  //res.send('respond with a resource');
  const users = await db.User.findAll();
  res.json( users );
});

// module.exports = router;
export default router;

呼び出し元(app.js)も変更する。

// var usersRouter = require('./routes/users');
import usersRouter from './routes/users';

17. ビルド後、データが取得できることを確認する

yarn build
yarn serve
  • localhost:3000/users にアクセスして、DBからデータが取得できることを確認する
[{"id":1,"name":"name1","birth":"2020-01-10T09:51:38.737Z","email":"mail1@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}
,{"id":2,"name":"name2","birth":"2019-01-10T09:51:38.737Z","email":"mail2@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}
,{"id":3,"name":"name3","birth":"2018-01-10T09:51:38.737Z","email":"mail3@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}]
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0