Understanding Atom Editor and Hacking It to Build a React App
My Attempt to Reuse Atom’s Core to Rebuild My Product Called Inkdrop
Hello, it’s Takuya here.
I’m developing a Markdown note-taking app called Inkdrop, whose some parts are based on Atom Editor for implementing plugin extensibility, UI theme support and flexible key customizations. Atom Editor is well-designed in code level so I could reuse their codebase easily than I imagined. As I mentioned in our current roadmap, I’m working on the ground-up improvements on Inkdrop. It’s been a while since I’ve read their code, so it would be time to catch it up and to learn from it.
After I’ve dug into Atom Editor’s core, I thought it would be great if I could rebuild Inkdrop completely based on it from scratch. So I’ve hacked Atom itself to make React able to work on it. I published my work on GitHub so you can try it:
You can check the commit to know what has changed from the original code. src/components/app-container.js
is the app container component where is a good place to start digging into it.
I guess it would be helpful if you are planning to create new React-based electron app that comes with features like plugin extensibility, UI themes and key customizations like Atom.
How to run it:$ git clone git@github.com:craftzdog/atom-react-app
$ cd atom-react-app
$ script/bootstrap
$ atom --dev --foreground
However, as a result, I ended up stopping to work based on it because:
- It bundles all source code in the app — I, a proprietary app developer, would like to hide my private code by minifying them. It looks like hard to accomplish that by changing its build process (I have made some changes already for it though).
- I found that it will be extremely hard to finish rebuilding the whole app from scratch — I admit it’s kind of over-engineering. Like a lot of other products tried to rebuild completely but failed, I could also fail since it will take very long time to finish. It should be more reasonable to borrow only some code as I did before.
But by touching Atom’s deep core, I’ve got to learn a lot from it. It was great. For example, I knew how Atom generates v8 snapshot in order to make the launch speed faster. And I found that their IPC helper module would be also useful for many electron projects.
How I Understood and Hacked Atom Editor
Followings are my progress notes about how I looked into Atom’s core and hacked it for my project, Inkdrop.
Their License
MIT License. Thanks Atom.
Build it
Follow the official documentations:> script/build
Node: v11.1.0
Npm: v6.2.0
Installing script dependencies
Installing apm
apm 2.1.3
npm 6.2.0
node 8.9.3 x64
atom unknown
python 2.7.13
git 2.17.2
Installing modules ✓
Wrote Dependencies Fingerprint: /Users/***/inkdrop/atom/node_modules/.dependencies-fingerprint 1a7626f47939d86d09695ab33831091b020a7347
Copying assets to /Users/***/inkdrop/atom/out/app
Transpiling packages with custom transpiler configurations in /Users/***/inkdrop/atom/out/app
transpiling for package github
Installing modules ✓
Transpiling Babel paths in /Users/***/inkdrop/atom/out/app
Transpiling CoffeeScript paths in /Users/***/inkdrop/atom/out/app
Transpiling CSON paths in /Users/***/inkdrop/atom/out/app
Transpiling PEG.js paths in /Users/***/inkdrop/atom/out/app
Generating module cache for /Users/***/inkdrop/atom/out/app
Generating pre-built less cache in /Users/***/inkdrop/atom/out/app/less-compile-cache
Generating metadata for /Users/***/inkdrop/atom/out/app/package.json
Generating API docs at /Users/***/inkdrop/atom/docs/output/atom-api.json
Dumping symbols in /Users/***/inkdrop/atom/out/symbols
Running electron-packager on /Users/***/inkdrop/atom/out/app with app name "Atom Dev"
Downloading electron-v2.0.12-darwin-x64.zip
[============================================>] 100.0% of 48.75 MB (7.5 MB/s)
Packaging app for platform darwin x64 using electron v2.0.12
Setting Atom Helper Version for /Users/***/inkdrop/atom/out/Atom Dev.app/Contents/Frameworks/Atom Helper.app/Contents/Info.plist
Copying non-ASAR resources to /Users/***/inkdrop/atom/out/Atom Dev.app/Contents/Resources
Writing LICENSE.md to /Users/***/inkdrop/atom/out/Atom Dev.app/Contents/Resources
Application bundle created at /Users/***/inkdrop/atom/out/Atom Dev.app
Generating snapshot script at "/Users/***/inkdrop/atom/out/startup.js" (3834)
Minifying startup script
Verifying if snapshot can be executed via `mksnapshot`
Generating startup blob at "/Users/***/inkdrop/atom/out/snapshot_blob.bin"
Moving generated startup blob into "/Users/***/inkdrop/atom/out/Atom Dev.app/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin"
Skipping code-signing. Specify the --code-sign option to perform code-signing
Skipping artifacts compression. Specify the --compress-artifacts option to compress Atom binaries (and symbols on macOS)
Skipping installation. Specify the --install option to install Atom
v8 Snapshot
The app launch speed is so fast! It looks like they generate v8 snapshot so that Chrominium can load JS faster.
- electron/mksnapshot: Electron mksnapshot binaries
- atom/electron-link: A module to bundle your electron app into a single file that can be used for V8 snapshots.
It installed all dependencies by apm
It gets errors when I installed dependencies with npm
because of node version mismatch. script/bootstrap
uses apm
to install modules. It takes care with node version of Electron. So they fetch apm
first. Amazing…
babel configurations
They made a transpiler for themselves. It includes babel-preset-react
so you can write jsx without worrying anything.
how should I adopt flux architecture
Maybe I could put files for redux in exports/
directory.
fetch main process logs
Run like so:$ atom --dev --foreground
Steps to load main process in dev mode
With atom --dev
option it launches /Applications/Atom.app
with dev mode enabled. In src/main-process/main.js
, the main process switches the file to require for dev mode. As a result, <workdir>/src/main-process/start.js
is loaded.
Creating windows
src/main-process/atom-window.js
:33
They just use BrowserWindow
as usual so I can change it to frameless.
Check loading PouchDB
Add:--- a/package.json
+++ b/package.json
@@ -137,6 +137,7 @@
"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",
"resolve": "^1.1.6",
Install it:> script/bootstrap
It failed. Maybe necessary to rebuild the native module:> npm install -g electron-rebuild
> electron-rebuild -v 2.0.12
Got it to work! It is loaded from main-process. Looks good.
Add a sidebar
Now I would like to add a sidebar for showing a list of notebooks. I copied tree-view
package to packages/side-bar/package.json
and edit it.
Successful. Interesting.
They don’t use React but etch to render UI
I saw a syntax like JSX in a package of welcome
but it is not actually react. It seems like etch, which is invented by Atom. So I can’t use React to build UI. Oh. Now, I have to rewrite whole views. How could I reuse Atom’s editor component? Hmm.
Looks like it would better implement views by myself
Atom’s editor is fascinating but it will lose the compatibility with Inkdrop’s existing plugins and I guess it can’t customize font size for headings. To reuse our existing codebase, I need React on Atom. Also I need a resusability on mobile, which is built with React Native. I would like to use Flow. Now, it looks like necessary to change compile-cache
.
For now, remove Atom’s default packages. Edit package.json
to “packageDependencies”:{}
. Then it launched, showing an empty window. Looks good.
Understanding how they provide UI for managing packages
apm
is a command-line tool but Atom provides GUI for managing atom packages. Investigate how they accomplish it.
It looks like settings-view
is the UI component. node_modules/settings-view/lib/install-panel.js
has an implementation of the installation UI.
In node_modules/settings-view/lib/package-manager.coffee
, there is a logic for managing packages, executing apm
directly: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
That’s what I guessed.. I found that apm
command supports --json
option so that you can use it programmatically.
Try rendering UI with React on Atom
Install react
, react-dom
and so on:--- 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",
Update babel-core
since transpiling won’t work well because babel
is too old. Also change the settings:--- 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"
+ ]
}
Hack atom-environment.js
like so:--- 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
}
Add a React component in src/components/app-container.js
:/** @babel */
import * as React from 'react'
export default function AppContainer () {
return <div>Inkdrop on Atom!</div>
}
It worked well. Awesome.
Loading styles
The entrypoint is static/atom.less
. It transpiles LESS files into CSS on-the-fly through less-compile-cache
. Now, where are they loaded from?
From src/theme-manager.js
:220 loadBaseStylesheets () {
221 this.reloadBaseStylesheets()
222 }
223
224 reloadBaseStylesheets () {
225 this.requireStylesheet('../static/atom', -2, true)
226 }
Okay, edit 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;
+}
It worked:
It would be great to develop new version by forking Atom, instead of just borrowing some code from it like before. I have easily confirmed its feasibility.
Getting errors when building it with ReactError: 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
I guess React causes the error: This browser doesn’t support requestAnimationFrame.
https://reactjs.org/docs/javascript-environment-requirements.html
It is necessary to avoid from running React when generating v8 snapshot. Maybe a shim works?global.requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};
Check if it’s possible to hide private code
Currently it bundles all source code in app.asar
. How to prevent this?
It looks like it loads the source directly in src/main-process/main.js
…
I guess I could use webpack to compile initialize-application-window.js
? But I suspect that it will become not possible to generate snapshot?
App with production build not launching
I don’t know but markdown-preview
causes the problem. If it doesn’t include markdown-preview
, it builds invalid asar file. When I tried to unpack the invalid asar, I got following error: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)
If I put an empty package named markdown-preview
, it just worked without problems. I don’t know what causes the problem. Maybe a bug of asar?
It also worked fine on Windows and Ubuntu.
Understanding Workspace
Todo
- Adopt eslint/prettier
- webpack
- Build demo version
- Understand code signing
Webpack
electron-link
rejects js built with webpack
: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
package.json
of markdown-preview
was different!--- /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
is left as .coffee
. I guess transpiling with babel
and coffee-script
was not being run.
Gotcha! Successfully required markdown-preview
. But another problem found: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
electron-link
doesn’t support modules loaded with require.resolve
. Like in src/workspace.js
here: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 )
Try adding scandal
package to the exclude list.
Passed! But I found there are many places where require.resolve
is used..that will cause problems when running, I guess.
Next problem: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)
Oh, does it not support ES6? It uses terser-js/terser: JavaScript parser, mangler, optimizer and beautifier toolkit for ES6+. I guess it should support ES6. It was no luck after having upgraded it to the latest version.
It was solved by setting webpack like so:optimization: {
nodeEnv: false
}
Next problem: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
Wait, wait. electron-link
does bundle dependencies just like webpack
! Well, only what I should do is to bundle the output file generated with electron-link + minify?
Plan B
I think it is dangerous if I continued to hack the current build process because I will not be able to catch up the latest version. Is it possible to minify only my code? Don’t let my code be copied during copy assets
step.
Another option would be to allow bundling my code. It is ok if it doesn’t affect any security risk.
Or, just not copy anything.
It would be good if dependencies can be required from electron-link
-ized code.
Bundle with electron-link
I found that electron-link also bundles dependencies in node_modules
. So, I no longer need webpack
. It also supports minify.
The problem is that it needs another working directory for storing transpiled files with babel and coffee-script. Run electron-link after transpiling. And output files to intermediate dirs with electron-link.
What about other files..
initialize-application-window.js is not necessary
So a way to build would be:
- Bundle dependencies with electron-link before packaging
- Delete unnecessary files
- Generate app package
Let’s try it.
A problem with bundling the source files of main process
It uses dynamic import at a lot of places, webpack doesn’t work well for bundling the entrypoint. So leave atom’s code as it is, bundle only inkdrop’s code with webpack.
Understanding atom-workspace
items means every pane possible to display: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 }
Maybe it supports nesting. But I don’t know what is dock. I guess it also supports drag-and-drop to change the layout. It supports a lot of features. But I don’t think I have to use it.
What about eslint and prettier
For now, add every file related to Atom to .eslintignore
.
Copy only dependencies for proddiff --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})
That’s it. Hope that helps.
Links
Homepage: https://inkdrop.app/
Send feedback: https://forum.inkdrop.app/
Contact us: contact@inkdrop.app
Twitter: https://twitter.com/inkdrop_app