20200909のNode.jsに関する記事は5件です。

社内ネットワークからIBM Watsonにつながらない

はじめに

社内ProxyのおかげでIBM WatsonのAPIが通らかったので対処法を記載します。
(今回はWatson Discoveryです)

結論

node-sdkのところに書いてありました。:open_hands:
Use behind a corporate proxy

npm install tunnel

前提条件

  • Node v10.16.3
  • npm v6.9.0
  • IBM CloudのWatsonDiscoveryのサービスが既にあり、collectionが作成済みであること

Discoveryについてはこちらの記事が参考になると思います。
Discoveryってなんぞ?という方はまずこちらの記事を見ることをおすすめします。
【2019/2月 全面更新!】Watson Discovery Serviceが日本語対応したので、触ってみた【SDUやってみた】編

社内ProxyのせいでAPIが通らないのなら、Nodeやnpmもインストールできないのでは・・・?
というご意見はごもっともですが、Node,npmはすでに実行できるという前提でお願いします。今回はあくまでIBM Watsonに焦点を当てます。

まずはWatsonのAPIを実行してみる

好きなディレクトリにて

npm init

何か聞かれますがすべてEnterでOK

Watson APIs Node.js SDK のインストール

Discoveryのインスタンスをクリックすると次のような画面が出ると思います。
その画面のAPIリファレンス→Nodeタブへ移ると記載があります
top.png
apire.png

npm install ibm-watson@^5.7.0

APIの実行

まずは簡単に今あるCollectionのリストを表示してみましょう。

APIリファレンスでは左側のMethods>Collection>List collectionのところに記載があります。
丁寧に右側にExample requestがあり、クリックでコピーができるようになっているのでコピーしましょう。
実行するファイルは適当にcollection.jsにします。

collection.js
const DiscoveryV1 = require('ibm-watson/discovery/v1');
const { IamAuthenticator } = require('ibm-watson/auth');

const discovery = new DiscoveryV1({
  version: '2019-04-30',
  authenticator: new IamAuthenticator({
    apikey: '{apikey}',//自身の情報に書き換え
  }),
  serviceUrl: '{url}',//自身の情報に書き換え
});

const listCollectionsParams = {
  environmentId: '{environment_id}',//自身の情報に書き換え
};

discovery.listCollections(listCollectionsParams)
  .then(listCollectionsResponse => {
    console.log(JSON.stringify(listCollectionsResponse, null, 2));
  })
  .catch(err => {
    console.log('error:', err);
  });

しかし、このままでは実行してもエラーが出てしまいます。
どこのDiscoveryのどのインスタンスに対してAPIを呼ぶかが記載されていないからです。
上記ソースコードの「//自身の情報に書き換え」をそれぞれ書き換えます(中括弧もいらない)

apikey,url
api,url.png

environment_id
environ.png

書き換えた後に実行

node collection.js

そうすると無事エラーが返ってきます。:v:

error: { Error: connect ETIMEDOUT 23.41.93.168:443
    at RequestWrapper.formatError (xxxxxxxxxx\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:224:21)
    at C:xxxxxxxxxxxxxxx\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:212:25
    at process._tickCallback (internal/process/next_tick.js:68:7)
  message: 'connect ETIMEDOUT 23.41.93.168:443',
  statusText: 'ETIMEDOUT',
  body:
   'Response not received - no connection was made to the service.' }

これでAPIを実行する環境ができました。

対処方法

node-sdkのところに書いてありました。:open_hands:
Use behind a corporate proxy
パッケージの「tunnel」を使ってね、とのこと
早速インストール

npm install tunnel

そしてgithubのExampleをみつつ

collection.js
const DiscoveryV1 = require("ibm-watson/discovery/v1");
const { IamAuthenticator } = require("ibm-watson/auth");
const tunnel = require("tunnel"); // https Agent

const httpsAgent = tunnel.httpsOverHttp({
  proxy: {
    host: "xxxxxx.com", //httpとかいらない
    port: 8080,
  },
});

const discovery = new DiscoveryV1({
  version: "2019-04-30",
  authenticator: new IamAuthenticator({
    apikey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    httpsAgent,
    proxy: false, 
  }),
  httpsAgent,
  proxy: false, 
  serviceUrl:
    "https://xxxxxxxxxxxxxx",
});

const listCollectionsParams = {
  environmentId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
};

discovery
  .listCollections(listCollectionsParams)
  .then((listCollectionsResponse) => {
    console.log(JSON.stringify(listCollectionsResponse, null, 2));
  })
  .catch((err) => {
    console.log("error:", err);
  });

そして実行すると・・・
※idなどの情報はマスクしました

{
  "status": 200,
  "statusText": "OK",
  "headers": {
    "content-type": "application/json;charset=utf-8",
    "access-control-allow-origin": "*",
    "access-control-allow-methods": "GET, PUT, POST, DELETE, OPTIONS",
    "cache-control": "no-cache, no-store, no-transform, max-age=0",
    "pragma": "no-cache",
    "expires": "0",
    "x-content-type-options": "nosniff",
    "x-xss-protection": "1",
    "content-security-policy": "default-src 'none'",
    "access-control-allow-headers": "Origin, Content-Type, Content-Length, Accept, X-Watson-Authorization-Token, X-WDC-PL-OPT-OUT, X-Watson-UserInfo, X-Watson-Learning-Opt-Out, X-Watson-Metadata",
    "strict-transport-security": "max-age=31536000; includeSubDomains;",
    "x-global-transaction-id": "4085110c3d0bc216af495b254da2ab8b",
    "x-dp-watson-tran-id": "4085110c3d0bc216af495b254da2ab8b",
    "content-length": "340",
    "x-edgeconnect-midmile-rtt": "165",
    "x-edgeconnect-origin-mex-latency": "222",
    "date": "Wed, 09 Sep 2020 13:27:25 GMT",
    "connection": "close"
  },
  "result": {
    "collections": [
      {
        "collection_id": "xxxxxxxxxxxxxxxxxxxx",
        "name": "test",
        "configuration_id": "xxxxxxxxxxxxxxxxxxxxx",
        "language": "ja",
        "status": "active",
        "description": null,
        "created": "2020-09-09T12:55:36.283Z",
        "updated": "2020-09-09T12:55:36.283Z"
      }
    ]
  }
}

めでたしめでたし:clap::clap:

終わりに

私が困っているようなことなんて、とっくにほかのだれかが困っていて解決策を出してくれているのできちんと公式のドキュメントをしっかり見よう!!
英語翻訳バンザイ:point_up:

DiscoveryのQueries>Query a collectionではまったとこ

クエリーの返り値フィールドを指定できるパラメーターの書き方がややこしくてはまった。
複数なのでリストかと思っていたら全然違かった。
正しくは下記

const queryParams = {
  environmentId: '{environment_id}',
  collectionId: '{collection_id}',
  _return:'id,metadata.name' //ここ
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MATERIAL-UIのMultiple SelectでChipから選択を解除する

はじめに

React + Typescript + MaterialUIでフロントエンドを作成していたときに実現したいことができなかったので参考程度に投稿します。

実現できなかった原因

Chipの×ボタンを押してもSelectのメニューが出てきてしまう

実現したいこと

MaterialUIの公式ドキュメントに書かれていた「Multiple Select(Chip)」でChipの×ボタンからも選択を解除したい!
last.gif

結論

Chipコンポーネントに以下プロパティを追加

onMouseDown={(event) => {event.stopPropagation();}}

前提条件

  • typescript,React,MaterialUiについてある程度の知識がある。
  • create-react-appでアプリケーションが作成済み
npx create-react-app {your_app_name} --template typescript
npm install @material-ui/core

Multiple SelectのChipを動かしてみる

まずは何も考えずコードをすべてコピーしてApp.tsxに貼り付ける。
次にChip以外のところは邪魔なのでChipに関連するものだけを残す。
そうするとコードは以下のようになります。

App.tsx
import React from 'react';
import { createStyles, makeStyles, useTheme, Theme } from '@material-ui/core/styles';
import Input from '@material-ui/core/Input';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import Chip from '@material-ui/core/Chip';

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    formControl: {
      margin: theme.spacing(1),
      minWidth: 120,
      maxWidth: 300,
    },
    chips: {
      display: 'flex',
      flexWrap: 'wrap',
    },
    chip: {
      margin: 2,
    },
    noLabel: {
      marginTop: theme.spacing(3),
    },
  }),
);

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250,
    },
  },
};

const names = [
  'Oliver Hansen',
  'Van Henry',
  'April Tucker',
  'Ralph Hubbard',
  'Omar Alexander',
  'Carlos Abbott',
  'Miriam Wagner',
  'Bradley Wilkerson',
  'Virginia Andrews',
  'Kelly Snyder',
];

function getStyles(name: string, personName: string[], theme: Theme) {
  return {
    fontWeight:
      personName.indexOf(name) === -1
        ? theme.typography.fontWeightRegular
        : theme.typography.fontWeightMedium,
  };
}

export default function MultipleSelect() {
  const classes = useStyles();
  const theme = useTheme();
  const [personName, setPersonName] = React.useState<string[]>([]);

  const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
    setPersonName(event.target.value as string[]);
  };

  return (
    <div>
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-mutiple-chip-label">Chip</InputLabel>
        <Select
          labelId="demo-mutiple-chip-label"
          id="demo-mutiple-chip"
          multiple
          value={personName}
          onChange={handleChange}
          input={<Input id="select-multiple-chip" />}
          renderValue={(selected) => (
            <div className={classes.chips}>
              {(selected as string[]).map((value) => (
                <Chip key={value} label={value} className={classes.chip} />
              ))}
            </div>
          )}
          MenuProps={MenuProps}
        >
          {names.map((name) => (
            <MenuItem key={name} value={name} style={getStyles(name, personName, theme)}>
              {name}
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

そしてこれをnpm startしてhttp://localhost:3000でみると
first.gif
よさそう!※拡大してます

Chipの×ボタンを表示する

Chipに×ボタンを表示するにはChipコンポーネントにonDeleteプロパティを追加すればいい。

Apptsx
<Chip 
key={value} 
label={value} 
className={classes.chip} 
onDelete={() => { alert(value) }} /> #ここを追

今回は×ボタンをがクリックされたことを確認するために、alertでクリックしたChipのラベルを表示するようにした。
そして再度npm start
second.gif

あれ...?何度押しても×ボタンがクリックできずにSelectのメニューが出てきてしまう。

対処法

Chipコンポーネントに以下プロパティを追加

App.tsx
<Chip 
  key={value} 
  label={value} 
  className={classes.chip} 
  onDelete={() => { alert(value) }}
  onMouseDown={(event) => {event.stopPropagation()}}  #ここを追加
/> 

そして再度npm start
third.gif

今度はきちんとクリックされてアラートが出ていますね。

Chip削除の処理を追加する

先ほど入れたalertの処理をChip削除(personName内の名前を削除)する処理に変える。

新しくchipDeleteという関数を用意する

 const chipDelete = (name: string) => {
    setPersonName(personName.filter(value => value !== name))
  }

そうするとApp.tsxfunction MultipleSelect()は以下のようになる

App.tsx
export default function MultipleSelect() {
  const classes = useStyles();
  const theme = useTheme();
  const [personName, setPersonName] = React.useState<string[]>([]);

  const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
    setPersonName(event.target.value as string[]);
  };
  const chipDelete = (name: string) => {
    setPersonName(personName.filter(value => value !== name))
  };

  return (
    <div>
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-mutiple-chip-label">Chip</InputLabel>
        <Select
          labelId="demo-mutiple-chip-label"
          id="demo-mutiple-chip"
          multiple
          value={personName}
          onChange={handleChange}
          input={<Input id="select-multiple-chip" />}
          renderValue={(selected) => (
            <div className={classes.chips}>
              {(selected as string[]).map((value) => (
                <Chip
                  key={value} label={value} className={classes.chip}
                  onDelete={(event) => chipDelete(value)}
                  onMouseDown={(event) => { event.stopPropagation(); }}
                />
              ))}
            </div>
          )}
          MenuProps={MenuProps}
        >
          {names.map((name) => (
            <MenuItem key={name} value={name} style={getStyles(name, personName, theme)}>
              {name}
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

そしてnpm start
last.gif

うまくいった!!!!:v:

終わりに

今思うとこんなにすっとできてしまうなんて。。。
ただ単にコピペするだけではなくてどのような処理が行われていて、どんなオプションのプロパティがあるのかを確認しないといけないですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デプロイコマンドを実行する際に対話形式で確認

デプロイのコマンドを実行する際に、環境ごとで確認をするためのスクリプトを書きます。
指定された入力があれば、そのあとの処理を続けて実行、指定と違えばそこで終了します。

package.json
{
  "scripts": {
    "deploy": "sh confirmation.sh STG && node deploy"
  }
}
confirmation.sh
#!/bin/bash

ENV_NAME=$1

function ConfirmExecution() {
  echo "${ENV_NAME}環境のスクリプトを実行しますか?"
  echo "実行する場合は${ENV_NAME}と入力してください"
  read input

  if [ -z $input ]; then
    ConfirmExecution
  elif [ $input = ${ENV_NAME} ]; then
    echo "スクリプトを実行します。"
  else
    echo "スクリプトを終了します。"
    exit 1
  fi
}

ConfirmExecution
deploy.js
console.log('deploy!!')

実行

$ npm run deploy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

いまさらNode.js入門

記事概要

環境構築まわりは誰か出来る人ひとりがやってしまえば
触る必要がない(むしろ触らないほうが良いくらい)ので
なかなか知識が付きにくい。
という事で少し勉強してみた事をまとめてみました!


Node.js とは


そもそもNode.jsとは何ぞやというところですが、
めちゃくちゃ簡単に言うと、サーバーサイドで動くJavaScript環境の事です。

と言葉で聞いてもピンと来ないので、実際にどういう事か
次のスライドで見てみましょう。


やっている事の説明は次のスライドで行っています。
qiita-test.gif


前のスライドでやっている事

  1. testを出力するスクリプトを作成
  2. スクリプトファイルをダブルクリックで実行しようとするとエラーが出る
  3. Node.jsを使用してコマンドラインから作成したスクリプトを実行するとtestが出力される

正確には違うかもしれませんが、
これがサーバーサイドで動くってことかぁ
となんとな~く感じでいただけたかと思います。

では次に、Node.jsでよく使用される
npmについて見ていきましょう。


npm とは


npmはパッケージ管理システムの一種です。

npmには凄い人たちが作った、
凄いモジュールが沢山あります。
Node.jsではそれらのモジュールをインストールする事で
使用することができるのですが、そのインストールの際
npmを使用します。


モジュールは依存関係を持っている事が多く、
モジュールAを使用するためにはモジュールBが必要で
そのモジュールBを使用するためにはモジュールCが~…
みたいなことが起きます:cry:


npmはこのような事を解決して
モジュールAをインストールする。と実行するだけで
そのモジュールを実行するために必要なモジュールを
併せてインストールしてきてくれます:relaxed:


モジュールの使用方法


実際にモジュールを使用してみましょう。
まずは、今回作業するディレクトリを作成してください。
今回、私はデスクトップにtestという
ディレクトリを作成して説明を行っていきます。

※ Node.jsはインストール済みを想定しています。
※ ターミナルはgit bashを使用しています。


まずは該当のディレクトリに移動して、
下記コマンドを打ってみましょう。

npm init

色々と入力を求められますが、すべてEnterで大丈夫です。
するとpackage.jsonというファイルができるので
このファイルを開いてみましょう。


package.jsonの中の"scripts"
"test"というscriptがあるかと思います。
この部分を下記の様に書き換えてみましょう。

  "scripts": {
    "test": "echo hello world !"
  }

そして、下記コマンドを実行すると「hello world !」が
表示されるはずです!

npm run test

これが基本的なnpm-scriptの実行方法です。


npm-scriptを実行する際はpackage.jsonがある
ディレクトリでnpm run [スクリプト名]
実行が可能です!

次はnpmでモジュールをインストールして
そのモジュールを使用したスクリプトを
作成していきましょう。


今回は例としてonchangeモジュールを
使用してみましょう。このモジュールはファイルの変更を
検知してくれるという機能になります。
下記コマンドでインストールを行いましょう。

npm install onchange

インストールが完了したのを確認したら
package.jsonを見てみましょう。すると、
"dependencies"という項目に"onchange"
追加されていると思います。これがあることで、
npm installというコマンドを打つだけで、
onchangeモジュールをインストールしてきてくれます。


つまり、複数人で開発を行う際package.json
共有されていれば、その階層でnpm installを行うだけで
"dependencies"にあるモジュール群を全てインストール
してきてくれるという仕組みです!

必要なモジュールをひとりひとりが一個ずつ
インストールする必要が無いのは、このおかげです。


それではインストールしてきたonchangeモジュールを
実際に使ってみましょう。詳細な使用方法は
公式にあるので、そちらを参考にしてください。

まずは今回使用しているディレクトリの中に、srcというディレクトリを作成してください。


次に、package.jsonを開いて先ほど編集した
"scripts""test"の箇所を下記の様に
変更してください。

  "scripts": {
    "test": "onchange src/* -- echo {{changed}}"
  }

先ほどのスクリプトでやっている事としては
下記のような感じです。

onchange [監視するファイル] -- [変更があったときに実行されるスクリプト]

今回は、srcディレクトリ内で、変更があったら
変更があったファイル名を出力する。
という単純なものです。

途中で使われている{{changed}}というのも、
onchangeモジュールの機能の一つで、
変更が検知されたファイルの
ファイル名を教えてくれます。


では、実際にスクリプトを実行してみましょう。

npm run test

すると、監視モードになると思うので、
作成したsrcディレクトリに適当なファイルを作成したり
編集したりしてみてください。
変更したファイル名が出力されたら成功です:sunglasses:


以上がNode.jsの簡単な説明になります!
今回使用したonchangeモジュールは使い方次第で
とても便利に使用できるので、とてもおすすめです。

今までNodeを使ってるけど、どんなものなのか
あまり理解してなかったので、同じような人の
助けになれば幸いです:blush:


お わ り

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSエコシステムぶらり探訪(2): Node.jsとCommonJS modules

JSエコシステムの進化を語るにはNode.jsを避けて通ることはできません。Node.jsと、それ自身の持つモジュール機能について歴史的な背景を踏まえつつ説明します。

←前 目次

Node.js

Node.jsは非同期I/Oを備えたサーバーサイドJavaScriptのための実行環境として2009年に登場しました。1 現在はサーバーサイドJavaScriptだけではなく、JavaScriptのビルド環境として無くてはならないものになっています。

要するにNode.jsは、PerlスクリプトやRubyスクリプトと同じようにJavaScriptのコードを実行するための環境です。

main.js
console.log("Hello, world!");
$ node main.js
Hello, world!

CommonJS modules (CJS)

CommonJS modulesはNode.jsで主に使われているモジュール形式です。CommonJSという規格群の一部として2009年に登場し、生まれて間もないNode.jsのモジュールシステムもすぐにCommonJSに適合しました。 2

後述するESM (ES Modules) で置き換えられつつあり、CJSのほうが伝統的な形式といえます。

util.js
var private_value = 42;
// exports.square = ... でもよい
module.exports.square = function(x) {
  return x * x;
};
main.js
var util = require('./util');
console.log(util.square(2)); // => 4
console.log(util.private_value); // => undefined

また、 module.exports に別の値を代入することもできます。この場合は exports にだけ代入しても有効ではないので注意する必要があります。

square.js
// module.exportsへの代入は必須。exportsにも代入しておくと後々便利
module.exports = exports = function(x) {
  return x * x;
};
// JavaScriptの関数はそれ自体オブジェクトなので、プロパティーに代入できる
exports.version = "0.1.0";

上の例では、 require は関数を返します。

main.js
var square = require('./square');
console.log(square(2)); // => 4
console.log(square.version); // => "0.1.0"

Node.jsにおいては最初に呼ばれるJavaScriptファイルもモジュールです。

main.js
var x = 42;
// global is Node.js equivalent of windows
// (There's also globalThis usable in both environments)
console.log(global.x); // => undefined

Node.jsのCJSの仕組み

CJSのrequireはNode.js (など、それぞれの処理系) が提供するプリミティブ関数ですが、その動作は比較的シンプルに理解できます。つまり、ファイルを発見して読み取り、関数に包んで eval する処理と考えることができます。3

実際にevalされるときは以下のような関数の本体として扱われます。(つまり、 exports, require, module, __filename, __dirname という5つのローカル変数があらかじめ存在するものとして扱われます。)

(function(exports, require, module, __filename, __dirname) {
  // ファイルの中身
});

moduleexports はあらかじめ以下のように初期化されたものと考えることができます。

var module = {}, exports = {};
module.exports = exports;
// その他、moduleの様々なプロパティーを設定

requiremodule オブジェクトをキャッシュしておき、eval終了後に module.exports の値を戻り値として返すと考えることができます。これにより module.exportsexports の関係についても説明がつきます。

モジュールの副作用とオブジェクトの同一性

以下のようなモジュールを考えます。

module1.js
console.log("Hello, world!");

var counter = 1;
exports.fresh = function() {
  return counter++;
};

このモジュールには以下の特徴があります。

  • モジュールのトップレベル処理に副作用がある。
  • モジュールが状態を持っている。

このような場合、モジュールの同一性を気にする必要が出てきます。全く同じ内容の module2.js をコピーとして作成し、以下のように main.js から呼び出してみます。

main.js
var module1 = require('./module1'); // => Hello, world!
var module2 = require('./module2'); // => Hello, world!

console.log(module1.fresh()); // => 1
console.log(module1.fresh()); // => 2
console.log(module2.fresh()); // => 1
console.log(module2.fresh()); // => 2
console.log(module1.fresh === module2.fresh); // => false

両方の console.log が実行され、 fresh は別々にカウントされ、 fresh のオブジェクトとしての同一性も false になりました。

Node.jsでは、パスが同じものは同一モジュールになります4。先ほどの main.js を書き換えて ./module1 を2回インポートするようにしてみます。

main.js
var module1a = require('./module1'); // => Hello, world!
var module1b = require('./module1'); // (no output)

console.log(module1a.fresh()); // => 1
console.log(module1a.fresh()); // => 2
console.log(module1b.fresh()); // => 3
console.log(module1b.fresh()); // => 4
console.log(module1a.fresh === module1b.fresh); // => true

console.log は1回しか実行されず、 fresh は同じカウンタを使うようになり、2つの fresh 関数はオブジェクトとしても同一になりました。

冠頭形モジュール

CJSのインポートは単なる require という関数であり、どこでも呼び出すことができます。これは一見すると便利で妥当な設計に見えますが、実際はNode.js以外の環境にモジュールシステムを移植するにあたってこの「どこでも呼び出せる」という性質が邪魔になってきます。

そこで、以降で解説するモジュールシステムの理解を助けるために、本稿独自の用語として「(CJSの)冠頭形モジュール」という概念を導入します5

定義. あるCommonJSモジュールが冠頭形である (is a prenex-form module) とは、以下を満たすことである。

  • そのモジュールファイルはヘッダ部と本体に分けられる。 (ヘッダ部に続いて本体が来るものとする)
  • ヘッダ部の各文は以下のいずれかの形式である。
    • var <変数名> = require(<文字列リテラル>);
    • let <変数名> = require(<文字列リテラル>);
    • const <変数名> = require(<文字列リテラル>);
    • require(<文字列リテラル>);
  • 本体では require 関数は使われていない。

冠頭形であれば、モジュールファイルの中身を実際にevalしなくても、あらかじめ依存先モジュールを決定することができます。

冠頭形ではないものの例としては以下のようなものがあります6

  • 条件つきインポート
  • require の引数が動的に決まるようなインポート
  • 当該モジュール読み込み時ではなく、あとで必要になってから行うインポート

まとめ

特に重要なのが以下の点です。

  • Node.jsによって「ブラウザー以外のJavaScript実行環境」が大きな地位を獲得した。
  • Node.jsによって、JavaScriptに優れたモジュールシステムがもたらされた。

このことがJavaScriptに2つの大きな課題をもたらしました:

  • Webブラウザーもモジュールシステムの恩恵を受けられるようにすること。
  • Node.jsとWebブラウザーの間のコードの相互運用性を高めること。

これらの課題がJavaScriptバンドラーの誕生、そして各種の新しいモジュールシステムの提案へとつながっていくと考えられます。が、次回はその前に、Node.jsのパッケージシステムについて扱います。

←前 目次


  1. Wikipediaの記述によると、それ以前にもサーバーサイドJavaScriptの技術自体は存在していたようです。 

  2. 根拠を探す余裕がなかったのでこのように書きましたが、実際のところNode.jsの初期のモジュールシステムをベースにしてCommonJSが生まれた可能性が高いと思います。 

  3. 他に、ファイルの読み取りが同期的に行われる点、複数回requireしたときにキャッシュする仕組み、巡回参照の処理などを考える必要がある 

  4. シンボリックリンクについては次回言及予定 

  5. これについて、より広く使われている名称があれば教えていただけるとありがたいです。 

  6. バンドラーによっては、ここに挙げたような例をうまく処理できてしまう場合もありますが、それでも一般的な場合を全てカバーするのは困難です。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む