(前回の続き: Atomコード再利用に向けた最新版の仕様調査)
個人で作っているInkdropというMarkdownノートアプリの改良に向けて、Atomのコードを再利用したい。
せっかく内部仕様を理解したし、いっそのことAtomをベースにアプリを組み直したら面白いんじゃないか?と思い立って、Atomを改造してReactが動くようにした。
GitHubにソースを公開したので、手っ取り早く手元で試したい人はそちらをどうぞ:
誰向けなのか: 今から新しいアプリを作ろうとしていて、Atomの高度なパッケージ拡張機能やテーマ機能を組み込みたい、あるいは真似したいという人は覗いてみると参考になるかもしれない。
動かし方は公式ドキュメントと同じ:
$ git clone git@github.com:craftzdog/atom-react-app
$ cd atom-react-app
$ script/bootstrap
$ atom --dev --foreground
改造してからしばらく経つので、もし動かなければ自分で解決してください。その技量がなければおすすめしない。
結果的にInkdropをこのプロジェクトに移植するのは諦めた。理由は次のとおり:
- 全ソースコードがアプリにバンドルされる仕様になっている
- プロプライエタリなアプリ開発者としては、プライベートなコードを難読化させておきたい
- そのためにビルド手順を変更するのは結構たいへんそう (途中までやった)
- 完全にイチからアプリを組み直すのは時間がかかりすぎて頓挫しそう
- Inkdropもなんだかんだで3年開発しているので、細かなところまでイチから組み直すのは相当大変
- 既存のコードを改善して部分的に拝借して再利用するのが現実的
ただ、今回の取り組みによってAtomの深いところまで理解できたので良かった。既にその意義は実感している。
例えば起動スピードを高速化するためにv8 snapshotをどのように生成して組み込んでいるのか、とか。
IPCのヘルパーモジュールなんかは一般的なElectronアプリにも広く使える便利なものだと思う。
作業記録
以降は、前回の続きの改造作業メモ。
Inkdropを組む前提でメモっていて、文脈が分かりづらいかもしれないので注意。
やっぱビューは自分で実装した方が良さげ
Atomのエディタは魅力的だが、現在のプラグインとの互換性は無くなるし、ヘディングのフォントサイズを大きくしたりとかは出来なさそうな感じがする。
Reactでレンダリングした方が自分のコード資産を再利用できる。
React Nativeとのコード共用性は保持したい。
Flowも使いたい。
そうすると compile-cache
周りの手入れが必要になってくるな。
とりあえずAtomの標準package群を全て外して空っぽにする。
package.json
を "packageDependencies":{}
と書き換え。
アプリを起動すると空っぽのウインドウが表示されるだけになった。エラーは特にない。良い。
プラグインのインストールUI調査
apm
はコマンドラインツールだがAtomはGUIでもパッケージを管理できる。
それはどうやっているのか調べる。
settings-view
パッケージが担当しているっぽい。
node_modules/settings-view/lib/install-panel.js
にインストールUIがある。
node_modules/settings-view/lib/package-manager.coffee
にパッケージの管理ロジックが書かれている。
直接apmコマンドを実行しているっぽい:
61 runCommand: (args, callback) ->
62 command = atom.packages.getApmPath()
63 outputLines = []
64 stdout = (lines) -> outputLines.push(lines)
65 errorLines = []
66 stderr = (lines) -> errorLines.push(lines)
67 exit = (code) ->
68 callback(code, outputLines.join('\n'), errorLines.join('\n'))
69
70 args.push('--no-color')
71
72 if atom.config.get('core.useProxySettingsWhenCallingApm')
73 bufferedProcess = new BufferedProcess({command, args, stdout, stderr, exit, autoStart: false})
74 if atom.resolveProxy?
75 @setProxyServersAsync -> bufferedProcess.start()
76 else
77 @setProxyServers -> bufferedProcess.start()
78 return bufferedProcess
79 else
80 return new BufferedProcess({command, args, stdout, stderr, exit})
81
やっぱそうなってくるか・・
apmコマンドに--json
オプションを付加して呼び出している。apm install --json
とかも出来るっぽい。よいね。
Atom上でReactを動かしてレンダリングする
react
react-dom
とかをインストール。
--- a/package.json
+++ b/package.json
@@ -34,7 +34,9 @@
"autocomplete-snippets": "https://www.atom.io/api/packages/autocomplete-snippets/versions/1.12.0/tarball",
"autoflow": "file:packages/autoflow",
"autosave": "https://www.atom.io/api/packages/autosave/versions/0.24.6/tarball",
- "babel-core": "5.8.38",
+ "babel-core": "6.26.3",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-react": "^6.24.1",
"background-tips": "https://www.atom.io/api/packages/background-tips/versions/0.28.0/tarball",
"base16-tomorrow-dark-theme": "file:packages/base16-tomorrow-dark-theme",
"base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme",
@@ -137,8 +139,11 @@
"pathwatcher": "8.0.1",
"postcss": "5.2.4",
"postcss-selector-parser": "2.2.1",
"pouchdb": "7.0.0",
"property-accessors": "^1.1.3",
"random-words": "0.0.1",
+ "react": "^16.6.3",
+ "react-dom": "^16.6.3",
"resolve": "^1.1.6",
"scandal": "^3.1.0",
"scoped-property-store": "^0.17.0",
babelが古くてトランスパイルが通らないのでbabel-core
をアップデート。設定も変更:
--- a/static/babelrc.json
+++ b/static/babelrc.json
@@ -1,7 +1,11 @@
{
- "breakConfig": true,
"sourceMap": "inline",
- "blacklist": ["es6.forOf", "useStrict"],
- "optional": ["asyncToGenerator"],
- "stage": 0
+ "presets": [
+ ["env", {
+ "targets": { "electron": "2.0.12" },
+ "useBuiltIns": "usage",
+ "debug": false
+ }],
+ "react"
+ ]
}
atom-environment.js
を以下のように改造する:
--- a/src/atom-environment.js
+++ b/src/atom-environment.js
@@ -43,6 +43,8 @@ const TextEditor = require('./text-editor')
const TextBuffer = require('text-buffer')
const TextEditorRegistry = require('./text-editor-registry')
const AutoUpdateManager = require('./auto-update-manager')
+const React = require('react')
+const { render, unmountComponentAtNode } = require('react-dom')
let nextId = 0
@@ -271,6 +273,15 @@ class AtomEnvironment {
this.observeAutoHideMenuBar()
this.disposables.add(this.applicationDelegate.onDidChangeHistoryManager(() => this.history.loadState()))
+
+ const AppContainer = require('./components/app-container').default
+ const root = document.createElement('div')
+ root.classList.add('app-container')
+ document.body.append(root)
+ const element = React.createElement(AppContainer)
+
+ render(element, root)
+ this.element = element
}
src/components/app-container.js
を追加:
/** @babel */
import * as React from 'react'
export default function AppContainer () {
return <div>Inkdrop on Atom!</div>
}
上手く動いた。素晴らしい。
スタイルの読み込み
static/atom.less
がエントリポイント。less-compile-cache
を通してオンザフライでCSSに変換して読み込んでいる。
ではこれはどこから読み込まれているのか?
src/theme-manager.js
から:
220 loadBaseStylesheets () {
221 this.reloadBaseStylesheets()
222 }
223
224 reloadBaseStylesheets () {
225 this.requireStylesheet('../static/atom', -2, true)
226 }
という訳で atom.less
をいじる:
--- a/static/atom.less
+++ b/static/atom.less
@@ -27,3 +27,12 @@
// Atom UI library
@import "../node_modules/atom-ui/atom-ui.less";
+
+.app-container {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 30px;
+}
できた:
前回の開発ではAtomのソースコードの一部を拝借して構築したが、今回はAtomをフォークして開発したほうがいろいろ都合がいいかもしれない。
そして意外にもあっさりと実現可能性が確認できた。
Reactを使用した状態でビルドするとエラーになる
Error: Cannot use `console` functions in the snapshot.
at Object.consoleNoop (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:98521)
at Object.../node_modules/scheduler/cjs/scheduler.production.min.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:14:1641204)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:99295)
at Object.../node_modules/scheduler/index.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:14:695932)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:99295)
at Object.../node_modules/react-dom/cjs/react-dom.production.min.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:14:128467)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:99295)
at Object.../node_modules/react-dom/index.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:11:415063)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:99295)
at Object.../src/atom-environment.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:102859)
at checkExecSyncError (child_process.js:601:13)
at Object.execFileSync (child_process.js:621:13)
at electronLink.then (/Users/***/Developments/local/inkdrop/atom/script/lib/generate-startup-snapshot.js:94:18)
at <anonymous>:null:null
エラーの箇所を見ると React が原因っぽい: This browser doesn't support requestAnimationFrame.
https://reactjs.org/docs/javascript-environment-requirements.html
なのでsnapshotを生成する時はReactのレンダリング部分を実行しないようにしてみる。
shimが必要・・?
global.requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};
ソースコードは隠蔽できるか
現状では app.asar
に全てのソースコードが同梱される仕様になっている。
なんとかそれは阻止できないだろうか。
src/main-process/main.js
を読んでもソースコードを直接読み込んでるっぽい・・
initialize-application-window.js
をwebpackなどでコンパイルすれば良いか。
でもそれだとsnapshotの効力がなくなってしまうのではないか?
いや、external設定で外部依存コードはバンドルしないようにすればいいか。
本番ビルドが立ち上がらない
markdown-preview
パッケージが影響しているっぽい。原因は不明。
markdown-preview
を含まない場合、不正なasarがoutputされる。asarをunpackしようとすると以下のようなエラーになる:
asar extract app.asar asarrr
undefined:1
{"files":{"benchmarks":{"files":{"benchmark-runner.js":{"size":2205,"offset":"0"}}},"dot-atom":{"files":{".gitignore":{"size":57,"offset":"2205"},"init.coffee":{"size":386,"offset":"2262"},"keymap.cson":{"size":1333,"offset":"2648"},"packages":{"files":{"README.md":{"size":60,"offset":"3981"}}},"snippets.cson":{"size":710,"offset":"4041"},"styles.less":{"size":712,"offset":"4751"}}},"exports":{"files":{"atom.js":{"size":1258,"offset":"5463"},"clipboard.js":{"size":275,"offset":"6721"},"ipc.js":{"size":273,"offset":"6996"},"remote.js":{"size":266,"offset":"7269"},"shell.js":{"size":263,"offset":"7535"},"web-frame.js":{"size":273,"offset":"7798"}}},"node_modules":{"files":{".dependencies-fingerprint":{"size":40,"offset":"8071"},"@atom":{"files":{"nsfw":{"files":{"build":{"files":{"Release":{"files":{".deps":{"files":{"Release":{"files":{"obj.target":{"files":{"nsfw":{"files":{"src":{"files":{"osx":{"files":{}}}}}}}}}}}},"nsfw.node":{"size":88796,"unpacked":true},"obj.target":{"files":{"nsfw":{"fil
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at Object.module.exports.readArchiveHeaderSync (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/lib/disk.js:90:24)
at Object.module.exports.readFilesystemSync (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/lib/disk.js:95:25)
at Object.module.exports.extractAll (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/lib/asar.js:191:27)
at Command.<anonymous> (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/bin/asar.js:66:15)
at Command.listener (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/node_modules/commander/index.js:315:8)
at emitTwo (events.js:106:13)
at Command.emit (events.js:194:7)
at Command.parseArgs (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/node_modules/commander/index.js:654:12)
at Command.parse (/Users/***/.nvm/versions/node/v7.9.0/lib/node_modules/asar/node_modules/commander/index.js:474:21)
ためしに markdown-preview
パッケージの中身を空っぽにしてみたが、特に問題なくビルドできた。
何が影響しているのかわからない。たぶんasarパッケージャのバグを踏んだのかもしれない。
無事 WindowsでもUbuntuでもビルドできた。
Workspaceの理解
Todo
- eslint/prettierとかの導入をどうするか
- webpack
- demo版のビルド
- code signingの理解
Webpack
webpackでビルドしたjsがelectron-linkに通らない。
Error: ENOENT: no such file or directory, open 'markdown-preview'
at Object.fs.openSync (fs.js:646:18)
at Object.fs.readFileSync (fs.js:551:33)
at /Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:30:27
at Generator.next (<anonymous>:null:null)
at step (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:3:191)
at /Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:3:361
at <anonymous>:null:null
正規のビルド方法と比較してみたところ、どうやら生成したjsそのものの問題ではなさそう。
markdown-preview
のpackage.json
のmainが違う!
--- /Users/***/Developments/local/inkdrop/atom/out.mine/app/node_modules/markdown-preview/package.json 2018-11-24 11:33:39.000000000 +0900
+++ /Users/***/Developments/local/inkdrop/atom/out/app/node_modules/markdown-preview/package.json 2018-11-24 11:22:15.000000000 +0900
@@ -16,20 +16,20 @@
"name": "markdown-preview",
"repository": {
"type": "git",
"url": "git+https://github.com/atom/markdown-preview.git"
},
"version": "0.159.25",
"_atomModuleCache": {
"version": 1,
"dependencies": [],
"extensions": {
- ".coffee": [
- "lib/main.coffee"
+ ".js": [
+ "lib/main.js"
],
".json": [
"package.json"
]
},
"folders": []
}
}
_atomModuleCache
がcoffeeのままだ。
babelとcoffee-scriptによるトランスパイルを実行していないからではないか。
あたり!無事markdown-preview
がrequireできた。
しかし別の問題が見つかった:
Unable to transform source code for module /Users/***/Developments/local/inkdrop/atom/out/app/node_modules/argparse/lib/argument_parser.js.
Error: /Users/***/Developments/local/inkdrop/atom/out/app/node_modules/argparse/lib/argument_parser.js
Cannot replace with lazy function because the supplied node does not belong to an assignment expression or a variable declaration!
at FileRequireTransform.replaceAssignmentOrDeclarationWithLazyFunction (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/file-require-transform.js:180:11)
at Context.visitIdentifier (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/file-require-transform.js:72:18)
at Context.invokeVisitorMethod (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:344:49)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:196:32)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:246:25)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:246:25)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:246:25)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at NodePath.each (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path.js:101:26)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:219:18)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:246:25)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at visitChildren (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:246:25)
at Visitor.PVp.visitWithoutReset (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:204:20)
at Visitor.PVp.visit (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:133:29)
at Object.visit (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/node_modules/ast-types/lib/path-visitor.js:101:55)
at FileRequireTransform.replaceDeferredRequiresWithLazyFunctions (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/file-require-transform.js:68:20)
at FileRequireTransform.apply (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/file-require-transform.js:25:10)
at /Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:57:56
at Generator.next (<anonymous>:null:null)
at step (/Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:3:191)
at /Users/***/Developments/local/inkdrop/atom/script/node_modules/electron-link/lib/generate-snapshot-script.js:3:361
at <anonymous>:null:null
require.resolve
しているやつが必要としているモジュールが、electron-linkに対応していない。
このあたり: src/workspace.js
:
1994 const task = Task.once(
1995 require.resolve('./replace-handler'),
1996 outOfProcessPaths,
1997 regex.source,
1998 flags,
1999 replacementText,
2000 () => {
2001 outOfProcessFinished = true
2002 checkFinished()
2003 }
2004 )
scandal
というパッケージを例外リストに入れてみる。
通った!しかし、require.resolve
を使っている箇所が沢山見つかるのが気になる・・おそらく実行時にエラーになりそうな予感。
次の問題:
Minifying startup scriptSyntaxError: Invalid assignment
at JS_Parse_Error.get (<anonymous>:75:23)
at process.<anonymous> (/Users/***/Developments/local/inkdrop/atom/script/build:56:19)
at emitTwo (events.js:126:13)
at process.emit (events.js:214:7)
at emitPendingUnhandledRejections (internal/process/promises.js:94:22)
at runMicrotasksCallback (internal/process/next_tick.js:124:9)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
おい・・。ES6に対応していないのでは。
terser-js/terser: JavaScript parser, mangler, optimizer and beautifier toolkit for ES6+を使っている。これはES6に対応しているはずなんだが。
最新版を使うようにしてみる。・・・no luck.
webpackに以下を指定することで解決:
optimization: {
nodeEnv: false
}
次の問題:
Verifying if snapshot can be executed via `mksnapshot`
/Users/***/Developments/local/inkdrop/atom/out/startup.js:1
var snapshotAuxiliaryData={};function generateSnapshot(){let process={};function get_process(){return process}function createElement(e){return{innerHTML:"",style:{}}}Object.defineProperties(process,{platform:{value:"darwin",enumerable:!1},argv:{value:[],enumerable:!1},env:{value:{NODE_ENV:"production"},enumerable:!1}});let documentElement={textContent:"",style:{cssFloat:""}},document={};function get_document(){return document}Object.defineProperties(document,{createElement:{value:createElement,enumerable:!1},addEventListener:{value:function(){},enumerable:!1},documentElement:{value:documentElement,enumerable:!1},oninput:{value:{},enumerable:!1},onchange:{value:{},enumerable:!1}});let global={};function get_global(){return global}Object.defineProperties(global,{document:{value:document,enumerable:!1},process:{value:process,enumerable:!1},WeakMap:{value:WeakMap,enumerable:!1},isGeneratingSnapshot:{value:!0,enumerable:!1}});let window={};function get
Error: Cannot require module "crypto".
To use Node's require you need to call `snapshotResult.setGlobals` first!
at require (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:1662)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2113)
at Object.crypto (/Users/***/Developments/local/inkdrop/atom/out/startup.js:22:174800)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at Object.../src/atom-environment.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:13981)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at Object.../src/initialize-application-window.coffee (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:212614)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at /Users/***/Developments/local/inkdrop/atom/out/startup.js:1:3515
at Object.../src/initialize-application-window.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:3604)
Error: Command failed: /Users/***/Developments/local/inkdrop/atom/out/Atom Dev.app/Contents/MacOS/Atom Dev /Users/***/Developments/local/inkdrop/atom/script/verify-snapshot-script /Users/***/Developments/local/inkdrop/atom/out/startup.js
/Users/***/Developments/local/inkdrop/atom/out/startup.js:1
var snapshotAuxiliaryData={};function generateSnapshot(){let process={};function get_process(){return process}function createElement(e){return{innerHTML:"",style:{}}}Object.defineProperties(process,{platform:{value:"darwin",enumerable:!1},argv:{value:[],enumerable:!1},env:{value:{NODE_ENV:"production"},enumerable:!1}});let documentElement={textContent:"",style:{cssFloat:""}},document={};function get_document(){return document}Object.defineProperties(document,{createElement:{value:createElement,enumerable:!1},addEventListener:{value:function(){},enumerable:!1},documentElement:{value:documentElement,enumerable:!1},oninput:{value:{},enumerable:!1},onchange:{value:{},enumerable:!1}});let global={};function get_global(){return global}Object.defineProperties(global,{document:{value:document,enumerable:!1},process:{value:process,enumerable:!1},WeakMap:{value:WeakMap,enumerable:!1},isGeneratingSnapshot:{value:!0,enumerable:!1}});let window={};function get
Error: Cannot require module "crypto".
To use Node's require you need to call `snapshotResult.setGlobals` first!
at require (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:1662)
at customRequire (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2113)
at Object.crypto (/Users/***/Developments/local/inkdrop/atom/out/startup.js:22:174800)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at Object.../src/atom-environment.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:13981)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at Object.../src/initialize-application-window.coffee (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:212614)
at __webpack_require__ (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:2443)
at /Users/***/Developments/local/inkdrop/atom/out/startup.js:1:3515
at Object.../src/initialize-application-window.js (/Users/***/Developments/local/inkdrop/atom/out/startup.js:1:3604)
at checkExecSyncError (child_process.js:601:13)
at Object.execFileSync (child_process.js:621:13)
at electronLink.then (/Users/***/Developments/local/inkdrop/atom/script/lib/generate-startup-snapshot.js:101:18)
at <anonymous>:null:null
ちょっと待て。electron-linkもwebpackと同じように依存モジュールをbundleしてるじゃん・・。
という事は、electron-link + minifyで作ったファイルを普通にアプリに含めればいいだけでは。
もちろん、require.resolve
問題はまだ残るが。
プラン2
ちょっとこれ以上現状のビルド手順に手を加えると、最新版にキャッチアップする時に死にそうではある。
そこで、自分の書いたコードだけminifyして難読化すると良いのではないか?
copy assetsでは自分のコードはコピーしない。
自分のコードだけをwebpackなどであらかじめパッケージするとか。
あるいは、もう隠すのは諦めるとか。
悪用されたところで対して影響ないし。
セキュリティ上問題なければそれでいいかな。
あるいはコピーしない。
electron-link化されたやつから外部依存コードが取れたらいいんだけど。
electron-linkでバンドルする
electron-linkはnode_modules
にある依存ファイルもバンドルしてくれることが判った。
という事は、もうwebpackを使わずにこれを使ってバンドルすれば良いことになる。
minifyも上手く動くようだし。
問題は、もう一つの作業ディレクトリを用意する必要があることだ。
babelやcoffeeなどをトランスパイルしたファイルを置く場所が必要になる。
一度トランスパイルしたファイルを出力して、それをelectron-linkにかける。
その後に、electron-linkでintermediate dirに出力する。
その他のファイルのコピーをどうするか問題
そもそも src
配下の initialize-application-window.js
は要らない
だから以下の手順を取れば良い:
- アプリのpackagingの前にelectron-linkでバンドリング
- 不要なファイルを削除する
- アプリのパッケージ作成
一旦この構成で組んでみることにする。
mainプロセスのソースファイルバンドル問題
dynamic importを多用しているので、エントリポイントを単純にwebpackでバンドルしても上手く動かない。
だからatomのコードはそのままにしといて、inkdropのコードだけをwebpackでバンドルするようにする。
今のところはそれを検証できないので、一旦そうするつもりで進めてみることにする。
別にatomのコードはminifyしなくても良いかもしれない。それは今後どんな変更を加えるかによるが。
atom-workspace
の理解
itemsは表示できる領域すべてを指すようだ。
218 this.panelContainers = {
219 top: new PanelContainer({viewRegistry: this.viewRegistry, location: 'top'}),
220 left: new PanelContainer({viewRegistry: this.viewRegistry, location: 'left', dock: this.paneContainers.left}),
221 right: new PanelContainer({viewRegistry: this.viewRegistry, location: 'right', dock: this.paneContainers.right}),
222 bottom: new PanelContainer({viewRegistry: this.viewRegistry, location: 'bottom', dock: this.paneContainers.bottom}),
223 header: new PanelContainer({viewRegistry: this.viewRegistry, location: 'header'}),
224 footer: new PanelContainer({viewRegistry: this.viewRegistry, location: 'footer'}),
225 modal: new PanelContainer({viewRegistry: this.viewRegistry, location: 'modal'})
226 }
たぶん入れ子に出来るようになっている。
しかし明示的な名前は無いような気がする。dockとは何なのだろうか。
たぶんドラッグとかにも対応しているので、かなり機能豊富な印象。
これをわざわざ再利用しなくてもいいんじゃないだろうか。
eslint、prettier関連をどうするか
とりあえずAtomのコードは地道に全て.eslintignoreに加える。
prod用のdependenciesだけコピーする
diff --git a/script/lib/copy-assets.js b/script/lib/copy-assets.js
index 27b5f086c..8dbf666ee 100644
--- a/script/lib/copy-assets.js
+++ b/script/lib/copy-assets.js
@@ -3,6 +3,7 @@
'use strict'
+const execSync = require('child_process').execSync
const path = require('path')
const fs = require('fs-extra')
const CONFIG = require('../config')
@@ -11,16 +12,23 @@ const includePathInPackagedApp = require('./include-path-in-packaged-app')
module.exports = function () {
console.log(`Copying assets to ${CONFIG.intermediateAppPath}`)
+
+ let depFiles = execSync('npm ls --prod --parseable')
+ .toString()
+ .split('\n')
+ .slice(1)
+ .slice(0, -1)
+
let srcPaths = [
path.join(CONFIG.repositoryRootPath, 'benchmarks', 'benchmark-runner.js'),
path.join(CONFIG.repositoryRootPath, 'dot-atom'),
path.join(CONFIG.repositoryRootPath, 'exports'),
- path.join(CONFIG.repositoryRootPath, 'node_modules'),
path.join(CONFIG.repositoryRootPath, 'package.json'),
path.join(CONFIG.repositoryRootPath, 'static'),
path.join(CONFIG.repositoryRootPath, 'src'),
path.join(CONFIG.repositoryRootPath, 'vendor')
]
+ srcPaths = srcPaths.concat(depFiles)
srcPaths = srcPaths.concat(glob.sync(path.join(CONFIG.repositoryRootPath, 'spec', '*.*'), {ignore: path.join('**', '*-spec.*')}))
for (let srcPath of srcPaths) {
fs.copySync(srcPath, computeDestinationPath(srcPath), {filter: includePathInPackagedApp, dereference: true})
以上。