ぶれすとつーる

だいたいjavascript

CSS&FP WG

本記事、ただの用語メモ。

cssの仕様しらべてたら「CSS&FP WGによって定められた〜」みたいに書いてあって、そういえばよく見るけどFP is 何?ってなったので調べてた時のメモ

FP = Formatting Properties.

らしい。

CSS&FP WG = Cascading Style Sheets and Formatting Properties Working Group

がWG名らしい。

最近の動向まとめたページみてたら

Style Activity Statement

Summary of Activity Structure See the CSS Home Page for up-to-date information about CSS and the specifications by the CSS Working Group.

The Working Group was called “CSS & FP WG” from 1997 to 2000.

って書いてあったので2000年以前の呼名だったみたいで今はCSS WGらしい。

公式はここっぽい

www.w3.org

exotic objectがhost objectの呼び名が変わったものという風潮

  • native object -> ordinary object
  • host object -> exotic object

って感じの解釈をよく聞くけど違うと思う。(誰も言ってなかったらごめんなさい)

es6上での定義

4.3.6 ordinary object

object that has the default behaviour for the essential internal methods that must be supported by all objects.

4.3.7 exotic object

object that does not have the default behaviour for one or more of the essential internal methods that must be supported by all objects.

NOTE Any object that is not an ordinary object is an exotic object.

http://people.mozilla.org/~jorendorff/es6-draft.html#sec-ordinary-object

全てのオブジェクトが持ってる必須な内部メソッドの振る舞いがデフォルトなやつがordinary object

それ以外(内部メソッドの振る舞いがデフォルトじゃないやつ)がexotic object

ってなってるはず。

es5.1の定義

4.3.6 native object

object in an ECMAScript implementation whose semantics are fully defined by this specification rather than by the host environment

NOTE Standard native objects are defined in this specification. Some native objects are built-in; others may be constructed during the course of execution of an ECMAScript program.

4.3.8 host object

object supplied by the host environment to complete the execution environment of ECMAScript

NOTE Any object that is not native is a host object.

http://www.ecma-international.org/ecma-262/5.1/#sec-4.3.6

となっていて実行環境ごとに作られるのがhost objectで、そうでないesによって実装されてるのがnative object.

なので

たとえばArrayとかはES5の定義ではnative objectだと思うんだけど、ES6の定義では[[DefineOwnProperty]]lengthを考慮するように変更されててデフォルトの振る舞いと違うのでexotic objectになる

http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array-exotic-objects

An Array object is an exotic object

requireの仕組み

こんばんは

この記事は Node.js Advent Calender 2014の23日目の記事です。

Node.js Advent Calendar 2014 - Qiita

普段node書くとき、何気なく使ってるrequireだけど、どんな風にモジュールが読み込まれてるのかコアコードの中を追ってみる。

https://github.com/joyent/node/blob/v0.11.14/lib/module.js#L362

Module.prototype.require = function(path) {
  assert(util.isString(path), 'path must be a string');
  assert(path, 'missing path');
  return Module._load(path, this);
};

こいつが各moduleが読み込まれた時にセットされるrequireの本体。

簡単なパラメータチェックをしてModule._loadに処理を渡している。

この時はまだpathのresolveなどはまだしていない。 単純な移譲。

module._load

Module._load = function(request, parent, isMain) {
  // ...省略

  // [A]
  var filename = Module._resolveFilename(request, parent);

  // [B]
  var cachedModule = Module._cache[filename];
  if (cachedModule) {
    return cachedModule.exports;
  }

  // [C]
  if (NativeModule.exists(filename)) {
    //...省略
    return NativeModule.require(filename);
  }

  // [D]
  var module = new Module(filename, parent);
  // ...省略
  Module._cache[filename] = module;

  // [E]
  var hadException = true;
  try {

    module.load(filename);
    hadException = false;
  } finally {
    if (hadException) {
      delete Module._cache[filename];
    }
  }

  return module.exports;
};

[A]

ここで初めてファイル名の解決が行われます。

Module._resolveFilenameというAPIを使ってパスを解決しています。

このAPIは第二引数のparent (requireを実行しているmodule自身)のパスから相対的に解決していきます(native moduleを除く)

[B]

ファイルのパスが先ほどの手順で解決されているのでこれをキーとして、すでにそのモジュールが読み込まれていてキャッシュが存在していればそれのexportsを返すというような実装になってます。

Module._cacheはfile名をキー、値にはmodule自身をつっこんでるキャッシュ用のオブジェクトです。

ここで注意したいのは返してるのはmodule.exportsの値だけです。

通常ロードされたモジュールに展開されるローカル変数moduleはその呼び出し元moduleのparentプロパティ( http://nodejs.jp/nodejs.org_ja/api/modules.html#modules_module_parent)をもってるはずですが、この辺はrequireの度に設定されなおしたりはしません。

なのでmodule.parentをたよりにした実装してるとこの辺でいつか死ぬのでやめといたほうがいい。

以前死にました。( module.parent.filename is cached. · Issue #6149 · joyent/node · GitHub )

[C]

ロード対象にされてるモジュールがnativeなモジュール(pathとかfsとかそういうやつ)かどうかを判定し、そうであればnativeモジュール用のローダーで読み込みます。 (https://github.com/joyent/node/blob/v0.11.14/src/node.js#L783)

[D]

ここで新たなモジュールとしてModuleのインスタンスを作ります。(ここで渡されてるparentmodule.parentとして永久に保持される)

そしてそれをそのままパスをキーとしてキャッシュします。

この段階では別にパスからソースをコンパイルしたりはしてません。

とくにコンストラクタ内にそういう処理はありません。

function Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  if (parent && parent.children) {
    parent.children.push(this);
  }

  this.filename = null;
  this.loaded = false;
  this.children = [];
}

[E]

ここでModule.loadを利用してソースをコンパイルし、module.exportsを返却してます。

この時読み込みに失敗したエラーはcatchはされないものの、その後のfinalyでcacheだけは綺麗に消されるので、ロード失敗時に変なキャッシュが残ることはないはずです。

次はソースをコンパイルするところを追います。

module.load

Module.prototype.load = function(filename) {
  // 省略

  // [A]
  var extension = path.extname(filename) || '.js';
  if (!Module._extensions[extension]) extension = '.js';

  // [B]
  Module._extensions[extension](this, filename);
  this.loaded = true;
};

[A]

拡張子ごとのローダーを利用するため、どのローダーを利用するかの判別のためにファイルパスから拡張子を抜き出します。 (デフォルト .js)

ローダーがないような拡張子の場合はとりあえず.js用のローダーで試すみたいです。

[B]

拡張子ごとのローダーによって読み込みを開始します。

Module.exteisons[extension]というのがローダーです。

通常我々が利用するのは.js.jsonくらいでしょうか。 あと一応.nodeというローダーもあるみたいです。

// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
  var content = fs.readFileSync(filename, 'utf8');
  module._compile(stripBOM(content), filename);
};


// Native extension for .json
Module._extensions['.json'] = function(module, filename) {
  var content = fs.readFileSync(filename, 'utf8');
  try {
    module.exports = JSON.parse(stripBOM(content));
  } catch (err) {
    err.message = filename + ': ' + err.message;
    throw err;
  }
};

.jsonのほうは簡単ですね。

ファイルを同期的に読み出してstripBOMutf-8のBOM(http://www.wdic.org/w/WDIC/UTF-8#BOM)を取り除いたものをJSON.parseしてオブジェクトにもどしてそれをmodule.exportsにセットしています。

.jsonはこれでおしまいです。

.jsのほうはもうちょっと複雑なのでBOMを排除したファイルコンテンツを取得したあと、module._compileに処理を移譲しています。

よくこのローダーはテストとかでrequireしたものをスタブに置き換えるために使われたりします。

javascript - How to stub require() / expect calls to the "root" function of a module? - Stack Overflow

ドキュメント上では廃止予定となってるけどコアコードに根深く存在してるので事実上これは廃止できませんみたいなこと書いてあるので複雑な感じですね。

でも、そういうことしたいとき、多分ほかの方法はvm使ったりとかもっと荒々しい方法とかになると思います。

module._compile

https://github.com/joyent/node/blob/v0.11.14/lib/module.js#L378

長かったけどこれで最後です。

Module.prototype._compile = function(content, filename) {
  var self = this;

  // [A]
  // remove shebang
  content = content.replace(/^\#\!.*/, '');

  // [B]
  function require(path) {
    return self.require(path);
  }

  require.resolve = function(request) {
    return Module._resolveFilename(request, self);
  };

  Object.defineProperty(require, 'paths', { get: function() {
    throw new Error('require.paths is removed. Use ' +
                    'node_modules folders, or the NODE_PATH ' +
                    'environment variable instead.');
  }});

  require.main = process.mainModule;

  // Enable support to add extra extension types
  require.extensions = Module._extensions;
  require.registerExtension = function() {
    throw new Error('require.registerExtension() removed. Use ' +
                    'require.extensions instead.');
  };

  require.cache = Module._cache;

  // [C]
  var dirname = path.dirname(filename);

  // 省略

  // create wrapper function
  // [D]
  var wrapper = Module.wrap(content);
  var compiledWrapper = runInThisContext(wrapper, { filename: filename });

  // 省略

  // [E]
  var args = [self.exports, require, self, filename, dirname];
  return compiledWrapper.apply(self.exports, args);
};

[A]

ソースからシェバン( #!/usr/bin/env node ←こういうの)があれば取り除きます

[B]

読み込まれるモジュールのローカル変数として使うrequireを定義します。

なかみは単純にmodule.requireです。

ここまででみてきたrequireと同じものです(属するmoduleは呼び元と呼び先とで違うけど)

requireのもつメソッド( http://nodejs.jp/nodejs.org_ja/api/globals#globals_require )を定義していきます。

require.resolveは中でModule._resolveFilenameに処理を移譲してますね。

これはmodule._loadの中でファイルパスを解決したメソッドです。

なのでrequire.resolveを使ってファイルパスを解決すればそのままモジュールのキャッシュキーが安全につくれたりします

あとはちらほら廃止になったapi用の対応がみられますね。

[C]

この読み込まれるモジュールのディレクトリパスを取得しています。

これが読み込まれるモジュールのローカル変数として使う__dirnameになります。

ちなみに__filenameはさきほどModule._resolveFilenameによって解決されたパスをそのままつかいます。

[D]

ソースをラップします。

以前この部分だけ記事にしました( Nodeのファイルスコープ - ぶれすとつーる )

実行コード(文字列)を

'(function (exports, require, module, __filename, __dirname) { ' + source + '\n});'

こんな感じでラップするものです。

こうすることで読み込まれるモジュールにスコープができ、あらかじめそこに存在するローカル変数を(引数にセットすることで)用意することができます。

そしてこうしてできたコード文字列をrunInThisContextコンパイルします。

runInThisContextvmモジュールのvm.runInThisContextと同じです。

var runInThisContext = require('vm').runInThisContext;

これは実行元のローカル変数とかにはアクセスできないけど同じglobalを共有形式のコード評価です。

第二引数で渡してるfilenameのオプションはスタックトレース時の表示用の情報です。

これで function (exports, require, module, __filename, __dirname { [source] } が得られました。

[E]

あとはそれぞれ引数( self.exports, require, self, filename, dirname )をapplyでセットして実行しています。

selfは自身のmoduleをさします。

module.exportsexportsが同じ参照のものだということがここからわかりますね。

しばしばモジュール内で

exports = function () { ... }

が期待した動きをしないけどなんで??みたいな質問がwebに溢れてますがこれをみれば一目瞭然ですね。

ただのローカル変数なんだから参照を切るような代入をしたらmodule.exportsに反映されなくなりますね、exportsにはなんのマジック的要素もありません。

module.exports = function () { ... }

を使いましょう。

長くなりましたが各モジュールのrequireの動きをおってみました。

途中横道にそれそうな処理は省略しましたがnative_moduleの解釈の仕方などもあるので見ると収穫があるかもしれません。

Argumentsと関数内の変数環境の関係

おはようございます。

この記事はJavascript Advent Calender 2014の22日目の記事です。

JavaScript Advent Calendar 2014 - Qiita

domenicのツイートをストーキングしてたら、とある話を拾った。

議題のコードはこれ

var f = function(a) {
  a = 'lol';
  console.log(arguments);
};

f(42);
// 実行結果
//  ["lol"]

Argumentsオブジェクトを普通のオブジェクトと思っているとここで違和感を感じる

もう一個例を見てみる

var f = function (a) {
  a = 'lol';
  console.log(b);
}

var b = {d: 10};
f(b.d);
// 実行結果
//  Object {d: 10}

違和感を感じた人は、多分この結果と同じように引数aはarguments[0]の値をコピー(今回はプリミティブ値なので)してるように考えるので、aを変更したところでarguments[0]自身には影響がないはずなのでは?って思ってしまうんだと思う。

さらに

var f = function(a) {
  arguments[0] = 'lol';
  console.log(a)
};

f(42);
// 実行結果
// 'lol'

これもArgumentsにとても詳しいおじさん以外きっと違和感を感じると思う。

これらの挙動を見るにArgumentsは普通のオブジェクトではない。

結構いろいろ変なやつっぽい。

仕様を見てみるとその内部的な動きがわかった。

Argumentsは内部的にCreateMappedArgumentsObject (ES5まではCreateArgumentsObject)の呼出しによって生成される。

ざっくりいうと、Argumentsオブジェクトに引数でセットされた値を引数インデックスをキーとしてセットしている。

そしてミソなのは、非strictモード化のときに、内部的にmapというオブジェクトを作成し、その中に引数にセットされた値を引数indexをキーとしてセットし、Argumentsから参照([[Get]])された時にmapの該当キーの値を返却する

(strictモード化では単純にArgumentsにセットされた値を返却するだけ)。

このmapに対する引数のセットの仕方が特殊で以下のように記述されてる

  1. Let g be MakeArgGetter(name, env).

  2. Let p be MakeArgSetter(name, env).

  3. Call the [[DefineOwnProperty]] internal method of map passing ToString(index) and the PropertyDescriptor{[[Set]]: p, [[Get]]: g,[[Enumerable]]: false, [[Configurable]]: true} as arguments.

単純に[[Value]]にセットするのではなくMakeArgGetter/Setterにenvと共に渡した結果を[[Getter]][[Setter]]にセットしてプロパティ定義をしている。

※ ここでいうnameは引数名 function fn(a, b){} だとしたら aやbという引数名にあたる

※ ここでいうenvはこのargumentsの存在する関数対する変数環境にあたる(所謂 変数オブジェクト)

このMakeArgGetter/Setterがこの一見変な挙動を生み出してる。

MakeArgGetterは以下のように記述されている

9.4.4.7.1 MakeArgGetter ( name, env) Abstract Operation

The abstract operation MakeArgGetter called with String name and environment record env creates a built-in function object that when executed returns the value bound for name in env.

適当な約: MakeArgGetterは変数環境envnameの値を返却するような関数を作る

es5では簡単にこんな風にかかれてる

  1. Let body be the result of concatenating the Strings "return ", name, and ";".
  2. Return the result of creating a function object as described in 13.2 using no FormalParameterList, body for FunctionBody, env as Scope, and true for Strict.

scopeにenvをセットするってかいてあるので擬似的に表現するとこんな感じになると思う。

function A(a, b) {
  // arguments[0]の[[Get]]は function () { return a; } 
  // arguments[1]の[[Get]]は function () { return b; } 
}

es6-draftの方ではMakeArgGetterの返す関数について

  1. Return the result of calling the GetBindingValue concrete method of env with arguments name and false.

となってるので挙動として同様の結果になるはず(GetBindingValueは変数環境から与えられたnameの値を返却する内部処理)

こう考えれば 最初の例(↓)

var f = function(a) {
  a = 'lol';
  console.log(arguments);
};

f(42);
// 実行結果
//  ["lol"]

のように変数aが'lol'に書き変わればarguments[0]の値もgetterを通して変数aが返却されてるだけなので同様の結果を返すということがわかる。

またMakeArgSetterは以下のように記述されてる

The abstract operation MakeArgSetter called with String name and environment record env creates a built-in function object that when executed sets the value bound for name in env.

適当な約: MakeArgSetterは変数環境envnamevalueをセットする関数を作る

es5では簡単にこんな風にかかれてる

  1. Let param be the String name concatenated with the String "_arg".

  2. Let body be the String "<name> = <param>;" with replaced by the value of name and <param> replaced by the value of param.

  3. Return the result of creating a function object as described in 13.2 using a List containing the single String param as FormalParameterList, body for FunctionBody, env as Scope, and true for Strict.

scopeにenvをセットするってかいてあるので擬似的に表現するとこんな感じになると思う。

function A(a, b) {
  // arguments[0]の[[Set]]は function (_arga) { return a = _arga; }
  // arguments[1]の[[Set]]は function (_argb) { return b = _argb; } 
}

es6-draftの方では、MakeArgSetterの返す関数について

  1. Return the result of calling the SetMutableBinding concrete method of env with arguments name, value, and false.

となってるのでこれもまた挙動的には同じだと思う(SetMutableBindingは変数環境に存在するnameの値内部にvalueをセットする内部処理)

こう考えれば 結構前の例(↓)

var f = function(a) {
  arguments[0] = 'lol';
  console.log(a)
};

f(42);
// 実行結果
// 'lol'

のようにarguments[0]が'lol'に書き変わればsetterを通して変数環境aに'lol'がセットされるので変数aも同様に値がかわってしまうことがわかる

とまぁ挙動に関してはここまででわかったけど辛いの'use strict'つけて回避したいですね。(callee, callerもアクセス拒否されるようになるし)

あとes6では...args(argumentsの単純な配列版)があるのでそれを使えばこの現象に遭遇することもないんでしょうね

おわりです。

サーバ側でd3を使って作ったsvgを画像に変換して返す

おはようございます、この記事はd3.js Advent Calendar 2014の21日目の記事です。

d3.js Advent Calendar 2014 - Qiita

つい先日からd3を使い始めました。

d3のpackage.json読んでたらnode側から使う場合はjsdomを使ってるっぽいのみつけた。 ドキュメントにも書いてあったけどサーバサイドでも普通にjsdom使ってdom操作的なやつできるらしい。

ならサーバサイドでデータを元にsvg組み立てて、それをnode-canvasに転写してpngなりに変換してstreamでレスポンスにながせるよねって思ったのでやってみた。

必要なモジュールのインストール

svgをnode-canvasに転写するのfabricが多分一番簡単なのでこれをいれる

でもその前にそれが依存してるnode-canvasのためにcairoいれる必要がある。

多分一番辛い作業だけどこの辺がんばってください

Home · Automattic/node-canvas Wiki · GitHub

このcairoがんばる作業が終わったらあとは普通に必要なモジュールをnpmからもってきます

npm install fabric

npm install d3

アプリケーションの作成

まずはサーバサイドでsvgを組み立てます

var d3 = require('d3')
  , body = d3.select('body')
  , svg
  ;

// 赤い丸を作る例
body
  .append('svg')
  .attr({width: 300, height: 300})
  .append('circle')
  .attr({cx: 150, cy: 150, r: 100, fill: '#ff0000'});

svg = body.node().innerHTML
console.log(svg);

// <svg width="300" height="300">
//   <circle cx="150" cy="150" r="100" fill="#ff0000"></circle>
// </svg>

これをfabricを使ってcanvasに転写する

// svg文字列から画像情報を読みこむ
fabric.loadSVGFromString(svg, function (objects, options) {
  var canvas, obj, stream;

  canvas = fabric.createCanvasForNode(300, 300);
  obj = fabric.util.groupSVGElements(objects, options);
  canvas.add(obj).renderAll();
});

あとはサーバ書いてレスポンスに垂れ流す 完成版

var http = require('http')
  , d3 = require('d3')
  , fabric = require('fabric').fabric
  ;

http.createServer(function(req, res) {
  var canvas = fabric.createCanvasForNode(300, 300)
    , body = d3.select('body')
    , svg
    ;

  body
    .append('svg')
    .attr({width: 300, height: 300})
    .append('circle')
    .attr({cx: 150, cy: 150, r: 100, fill: '#ff0000'});

  svg = body.node().innerHTML;

  fabric.loadSVGFromString(svg, function (objects, options) {
    var obj, stream;

    obj = fabric.util.groupSVGElements(objects, options);
    canvas.add(obj).renderAll();
    stream = canvas.createPNGStream();
    stream.on('data', function(chunk) {
      res.write(chunk);
    });

    stream.on('end', function() {
      res.end();
    });
  });
}).listen(3000);

サーバ起動して該当ページ ( http://localhost:3000/ )にアクセスすると日の丸ができてるはず。

表示

f:id:nazomikan:20141221075206p:plain

それっぽいやつ

// ...

  // それっぽいデータ
  color = d3.scale.category20();
  data = [5, 10, 2, 20, 5, 8, 13, 25, 26, 29, 22, 6];

  body
    .append("svg")
    .attr({width: width, height: height})
    .append('g')
    .selectAll('rect')
    .data(data).enter()
    .append('rect').attr('x', function (d,i) { return (i * 25) + 5 })
    .attr('y', function (d,i) { return height - (d * 10) })
    .attr('width', 20).attr('height', function (d, i) { return d * 10 })
    .attr('fill', function (d, i) { return color(i); });

  svg = body.node().innerHTML;

fabric.loadSVGFromString(svg, function (objects, options) {
  // ...

表示

f:id:nazomikan:20141221084021p:plain

それっぽいですね!><

YUIの開発終了とYUICompressor

Important Announcement Regarding YUI

この記事でYUIの積極的なメンテナンスがもうなされないよみたいな話を聞いてYUI Compressorもメンテされなくなるのかなーなんて思って聞いてみたんだけどYUI Compressorの管理は2012年の時点でownershipがかわってたみたいで、もうずいぶんと前からYAHOO主体の管理ではなかったみたい

今のメインメンテナはJoey Smithって方がしてるみたいで今後もメンテナンスやめる予定はないとのこと

まだ今すぐというわけではないけど時期バージョンv2.4.9も、現在抱えてる問題を解決できたら出すみたい

Will you release v2.4.9? · Issue #158 · yui/yuicompressor · GitHub

socket.ioで特定ユーザーにemitしたい時

最近socket.ioがメジャーバージョンになって少しかわって

今まで

io.sockets.socket(id).json.emit('msg', send_msg);

みたいな感じでかけてたのですがsockets (namespace)がsocketメソッドを持たなくなってて、「 あれ特定ユーザ探す方法なくね」って思ってたんだけどドキュメントよんでたら

Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id. > For your convenience, each socket automatically joins a room identified by this id.

This makes it easy to broadcast messages to other sockets:

Socket.IOの各ソケットはランダム、推測できない、ユニークな識別子のソケット#IDで識別されます。あなたの便宜のために、各ソケットは自動的にこのIDで識別される部屋に参加します。 これにより、簡単に他のソケットにメッセージを配信することができる

ってあるの見つけた。

各socketは自動的にIDで識別される部屋に参加するってあるっていってるのでそのルームに対してemitするのってどうしたらいいんだろっておもったらその辺うまくやってくれるsocket#to見つけた。

(メジャーバージョン以前からこのAPIはあったんだけど)

Socket.prototype.to =
Socket.prototype.in = function(name){
  this._rooms = this._rooms || [];
  if (!~this._rooms.indexOf(name)) this._rooms.push(name);
  return this;
};

渡されたname(sokecet#id)を見て次の通信のためのroomを指定できる感じになってる そして実際に送信するsocket#emitみると

Socket.prototype.emit = function(ev){
  if (~exports.events.indexOf(ev)) {
    emit.apply(this, arguments);
  } else {
    var args = Array.prototype.slice.call(arguments);
    var packet = {};
    packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT;
    packet.data = args;

    // access last argument to see if it's an ACK callback
    if ('function' == typeof args[args.length - 1]) {
      if (this._rooms || (this.flags && this.flags.broadcast)) {
        throw new Error('Callbacks are not supported when broadcasting');
      }

      debug('emitting packet with ack id %d', this.nsp.ids);
      this.acks[this.nsp.ids] = args.pop();
      packet.id = this.nsp.ids++;
    }

    if (this._rooms || (this.flags && this.flags.broadcast)) {
      this.adapter.broadcast(packet, {
        except: [this.id],
        rooms: this._rooms,
        flags: this.flags
      });
    } else {
      // dispatch packet
      this.packet(packet);
    }

    // reset flags
    delete this._rooms;
    delete this.flags;
  }
  return this;
};

となってて基本的に対象となるroomに対してイベントを配信してるっぽい。

※送信後roomは都度消去される

ということなんで最初かいてたこれ

io.sockets.socket(id).json.emit('msg', send_msg);

これをroomを使ったイベント配信に書き換えると

socket.to(id).json.emit('msg', send_msg);

みたいにできてよしなに動いた。

Namespaceにも同様の実装の#toあったり、Serverもdefault namespace .of('/') のtoにaliasはってあるのでこんな感じにサーバーから直接呼ぶ事もできる

io.to(id).json.emit('msg', send_msg);