こんにちは、Webpackでのbundle化初心者です。
今までgulpで分けたJSファイルをconcatして一つにまとめていました。gulpのconcatだとファイル名を01-
みたいなprefixをつけて結合順をコントロールしてました。webpackだとその辺りも解決してくれるっぽいので良いですね。(バンドルするための処理が乗るので最終的なコード量は多くなると思いますが
今回自分で分割したファイルを読み込ませていてwebpackでは問題なくbundleされたファイルが生成されたけど、ブラウザで確認すると Cannot assign to read only property 'exports' of object
というエラーが発生したのでメモ。
import
と module.exports
が混在してるとよろしくないっぽい
モジュールの化はES6のimport / export
の組み合わせと、CommonJSのmodule.exports / require
があり、これらが混在してしまうのがよろしくないようです。
ただ、require
は import / export
と使っても問題ないようです。
e.g
import / export
と module.exports
が混在するとエラー
// config.js module.exports = {name: '佐倉 千代'}; // name.js import config from './config'; module.exports = '野崎 梅太郎'; // app.js import name from './name'; console.log(name);
↓
webpackでbundle.jsは生成されるけどブラウザで確認すると
Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
name.js
で import
とmodule.exports
が混在しているのでNG
import / export
の組み合わせにすればOK
// config.js export default {name: '佐倉 千代'}; // name.js import config from './config'; export default config.name; // app.js import name from './name'; console.log(name);
→ 佐倉 千代
問題なく実行される
module.exports
されているものをimport / require
して export
するのはエラーにならないっぽい
// 'a.js' module.exports = { a: 'b' }; // b.js const a = require('./a.js').a; export default { aa: a }Gives error:
Cannot assign to read only property 'exports' of object '#<Object>'
Appeared after upgrade webpack 2.2.0.rc.6 -> 2.2.0.
とあったのですが、
試していたWebpack v4 の環境ではmodule.exports
されたものを読み込んでexport
してもエラーにはならなかったので仕様が変わったのかもしれません。
// config.js module.exports = {name: '佐倉 千代'}; // name.js import config from './config'; export default config.name; // app.js import name from './name'; console.log(name);
→ 佐倉 千代
require / module.exports
の組み合わせにしてもエラーになる場合がある
require / module.exports
の組み合わせにすればOKかと思ったのですが、
require
したオブジェクトをそのままmodule.exports
しているとエラーになるようです。
require / module.exports
で統一されてるけどエラーになるパターン
// config.js module.exports = {name: '野崎 梅太郎'}; // name.js const config = require('./config'); module.exports = config.name; // app.js const name = require('./name'); console.log(name);
→ Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
最終的な部分がimport
文でもエラー
// config.js module.exports = {name: '野崎 梅太郎'}; // name.js const config = require('./config'); module.exports = config.name; // app.js import name from './name'; console.log(name);
→ Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
経由しているファイル(name.js
)で読み込んでいるモジュールがexport
だろうと、読み込んだ内容をmodule.exports
していればエラー
// config.js export {name: '野崎 梅太郎'}; // name.js const config = require('./config'); module.exports = config.name; // app.js const name = require('./name'); console.log(name);
→ Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
// config.js export {name: '野崎 梅太郎'}; // name.js const config = require('./config'); module.exports = config.name; // app.js import name from './name'; console.log(name);
→ Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
module.exports
が読み込んだ内容でなければOK
// config.js module.exports = {name: '野崎 梅太郎'}; // name.js const config = require('./config'); module.exports = '御子柴 実琴'; // app.js import name from './name'; console.log(name);
→ 御子柴 実琴
問題なく実行される
※ config.js
が export
でも、app.js
はrequire
でもエラーにはならない
require
はimport / export
と混在しても常にOK
// config.js module.exports = {name: '堀 政行'}; // name.js const config = require('./config'); export default config.name; // app.js import name from './name'; console.log(name);
→ 堀 政行
問題なく実行される
require
とimport
が同じファイル内で混在していても問題ないので次のような感じでも問題なくbundleされて実行もできる
// config.js module.exports = {name: '堀 政行'}; // name.js cost $ = require('jquery'); import config from './config'; config.name = '鹿島 遊'; export default config.name; // app.js const config = require('./config'); import name from './name'; console.log(name);
→ 鹿島 遊
問題なく実行されるけど、import
とrequire
が同じファイルで混在してると見通しよくないので良くないって感想。
まとめ
- ファイル内がエラーにならない組み合わせであればOK
import / export
かimport / require / export
の組み合わせで統一するrequire / module.exports
での組み合わせで統一する- 但し
require
で読み込んだオブジェクトをmodule.exports
するとエラー
- 但し
import
とmodule.exports
が同じファイルにあるとエラー
module.exports
はトラップが多いので使わないほうが良さそう。という感想です。
と、THE Webpack 初心者って感じのエラーでした。
EMS (ES module)の世界と CJS (CommonJS)の世界があって混在してるって訳ですね。
JavaScriptもブラウザのECMAScriptとnode.jsの世界があって仕様がそれぞれ違うってのと近い感じでしょうか…
昨今のJS界隈の流れとか歴史とか含めた仕様の違い理解してないとハマりポイントっぽいって印象です。 (IEのJScriptに悩まされる事は減ったけど
絶対王者jQueryが倒れ、世は将にJSフロントエンド戦国時代!
(ここ数年は勢力図が落ち着いてる感じっぽいですが、その感離れていたのでキャッチアップが大変です
[参考]
- Cannot assign to read only property 'exports' of object '#<Object>' (mix require and export) · Issue #4039 · webpack/webpack · GitHub
- Babel 7 Upgrading creating error: “TypeError: Cannot assign to read only property 'exports' of object '#<Object>'” | stackoverflow
- babel+webpackな環境でESM(import構文)とCJS(module.exports構文)を混在させると『Cannot assign to read only property ‘exports’ of object ‘#<Object>’』と怒られる - ひと夏の技術
import / exports
と module.exports / require
について
- Node.js: exports vs module.exports
- Node.js : exports と module.exports の違い(解説編) - ぼちぼち日記
- ES6のexportについて詳しく調べた - Qiita
違いを理解していないので、いずれ...
最近作業中 月刊少女野崎くん 見てました。面白いよね