-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathindex.html
More file actions
executable file
·422 lines (317 loc) · 15.7 KB
/
index.html
File metadata and controls
executable file
·422 lines (317 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
<!doctype html>
<html>
<head>
<link href='https://fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>Reason Project</title>
<!-- Flatdoc -->
<script src='support/vendor/jquery.js'></script>
<script src='legacy.js'></script>
<script src="highlightJs/build/highlight.pack.js"></script>
<link href='highlightJs/src/styles/xcode.css' rel='stylesheet'>
<link rel="stylesheet" href="./octicons/octicons.css">
<script src='flatdoc.js'></script>
<!-- Flatdoc theme -->
<link href='theme-white/style.css' rel='stylesheet'>
<script src='theme-white/script.js'></script>
<link href='support/theme.css' rel='stylesheet'>
<script src='support/theme.js'></script>
<script id="markdown" type="text/markdown" src="index.html">
# ReasonProject
Installation of [`Reason`](http://facebook.github.io/reason/) project and
development environments via `npm`.
> Requirements: `npm` (currently tested on Mac, Linux, and Windows Linux subsystem).
`ReasonProject` installs the `Reason` toolchain into a local directory using
`npm`. `ReasonProject` can therefore be used as a template for new projects,
but can also be used to install the toolchain [into the global
environment](#editor-support). `ReasonProject` includes: the
compiler toolchain, the source formatter, REPL, and IDE support for popular
editors.
> A sandboxed environment models dependencies and builds them into a local
> directory so that it works reliably for anyone. Installing tools into your
> global environment is simply a matter of sourcing the sandboxed environment
> in your `.bashrc`. It's easy to make sandboxed local environments global, and
> very hard to do the reverse, so `ReasonProject` starts with local
> environments.
[](https://travis-ci.org/reasonml/ReasonProject)
## Install
Install by cloning the repo and running `npm install`. This installs all
dependencies locally into the `ReasonProject` directory.
```sh
git clone https://github.com/reasonml/ReasonProject.git
cd ReasonProject
npm install
```
> Note: Disable any `ocaml` global compilers you have in your `PATH`. If you already
have an ocaml compiler installed via `opam`, disable the line in your `~/.bashrc`
that sources the `opam` environment. You may even want to uninstall any `ocaml`
compilers that you installed via `brew`. (We are working on a fix to this problem).
## Project Commands
Once built, `ReasonProject` generates an *environment* that you can temporarily
load when executing commands. The environment contains an enhanced `PATH`
containing binaries built by your dependencies, but this environment isn't
loaded into your global path. Some `npm run` commands have been setup to allow
you to run some basic tasks, as well as any custom command, all within the
project environment.
### Run, Change, Rebuild
There are a couple of built in commands declared in `package.json` that you
can execute via `npm run`. For example: `"npm run start"`, `"npm run
reasonBuild"` and `"npm run clean"`. You can also
[add your own](#add-your-own-scripts) named scripts which give you a nicer
alias like `npm run myScriptName`.
```sh
npm run reasonBuild # Rebuilds after changing
npm run start # Runs the compiled app
npm run clean # Clean if you need to!
```
A single test file `./src/Test.re` is included. Make a simple change to it and
then run the commands above to see it effect the output.
### REPL
The `rtop` REPL is built into the sandbox. The command `npm run top` starts the
REPL.
```sh
# Opens `rtop` from the sandbox.
npm run top
```
### Custom Commands
To do anything beyond those basic, preconfigured commands, you just prefix your
command with `npm run env --`. You should pass the *actual* command you want to
run after `--`.
```sh
# By default nothing is found!
which refmt
> Not Found!
# Prefix with "npm run env --" and it finds it!
npm run env -- which refmt
> ~/ReasonProject/node_modules/reason/_build/ocamlfind/bin/refmt
```
If this becomes tedious, you can [add your own](#add-your-own-scripts) named
scripts so that you can do `npm run yourScriptName` instead.
## Editor Support
#### Prepare Your Editor
All of the IDE plugins, including integration with error highlighting,
autocomplete, and syntax highlighting are included inside of the built project.
Configure your `EDITOR` to load the `Reason` plugins from your instance of
`ReasonProject`. See the instructions for
[Atom](http://facebook.github.io/reason/tools.html#merlin-atom) and
[Vim](https://github.com/facebook/reason/tree/master/editorSupport/VimReason) and
[Emacs](https://github.com/facebook/reason/tree/master/editorSupport/emacs).
#### IDE support included.
The editor config above mostly exists to load the *actual* editor support, from
the `ReasonProject` build. The only thing we need is to make sure the `PATH`
contains all the important stuff from `ReasonProject`'s build. There are two
approaches: one continues to avoid global variables (as we've done so far), and
the other doesn't.
##### Avoiding Global Paths
You can continue to develop entirely in the isolated sandbox without polluting
global environment variables, by opening your editor within the sandbox
environment:
```sh
npm run env -- vim
npm run env -- atom
npm run env -- mvim
npm run env -- emacs
```
Because you've [prepared your
editor](#editor-support)
to load editor support from the environment, `npm run env -- yourEditor`
ensures that your editor will find the editor support in your environment
variables.
> Note: If you use `atom`, and already have `opam` installed, then there's a
> known issue where `atom` has problems loading, but you can fix it easily by
> commenting out any part in your `bashrc` that sources opam environments. We
> will come up with a long term solution at some point.
> Note: On MacOS, `emacs` may refer to the system emacs, which is often not
> the variant you've installed. To open standard emacs for example, run `npm
> run env -- open -a Emacs`
##### Using Global Paths
Pure sandboxed based development doesn't always work for certain workflows.
(prefixing *all* commands with `npm run` may not work well). In that case, you
can easily inject your successfully built project's environment into the global
`PATH`, by putting the following in your `.bashrc`:
```sh
# In your .bashrc
pushd ~/pathTo/ReasonProject/ && \
eval $(~/pathTo/ReasonProject/node_modules/.bin/dependencyEnv) && \
popd
```
## Developing Your Project
### Making It Yours
`ReasonProject` is meant to be the starting point of your own project. You'll want
to make use of existing libraries in your app, so
browse the growing set of `opam` packages ported to `npm` under
[`opam-alpha`](https://www.npmjs.com/~opam-alpha#packages). If there's something
that hasn't yet been ported from `opam`, make a pull request to
[this repo](https://github.com/yunxing/opam-npm/) and the package will automatically
be ported (as soon as the daemon picks it up).
##### Add Another Dependency
**Option `1`:** Install a dependency into the project sandbox, and use `--save`
so that your `package.json` is updated.
```sh
npm install --save @opam-alpha/cstruct
```
**Option `2`:** Edit the `package.json` manually to include your new dependency and run `npm install`.
> Note: Sometimes options `1` and `2` above fail because some *other*
> dependency that is rebuilt as a result of the `install` was not designed to
> build in an idempotent manner. In that case, just add the new dependency to
> your `package.json` `"dependencies"`, `rm -r node_modules`, and then run `npm
> install`. This installs from a clean slate.
> Note: `opam-alpha` is "alpha" - we may move to a new namespace `opam-beta`
> once we apply the lessons we've learned from `opam-alpha`. All the should
> exist as they are, but a next generation `opam-beta` universe on `npm` would
> have everything `opam-alpha` has (and then some). The work to upgrade your
> projects will likely be minimal.
This merely adds and builds the dependency. It doesn't mean your build system
will know to link to it. Accomplishing that is build system dependent, but if
using the example build system (`rebuild`, which is based on `ocamlbuild`), you
can get an idea for the options by doing `npm run buildHelp`. Typically you
need to configure the `reasonBuild` entry in `package.json` to add the `-pkg
dependencyPackage`. Consult your dependency's docs.
### Add Your Own Scripts
`npm` allows `scripts` to be specified in your project's `package.json`. These
`scripts` are a named set of commands. A few scripts have special meaning, such
as the `postinstall` script.
> The `postinstall` script is how your project compiles itself. It is
> guaranteed that the `postinstall` script executes any time you run `npm
> install` in this package, or any time another package installs you as a
> dependency. You're also guaranteed that your `postinstall` script is executed
> *after* all of your dependencies' `postinstall` scripts.
You can add new named scripts in the `package.json` `scripts` field. Once
added, you can then run them via `npm run scriptName` from within the project
root.
###### Making Sure Your Scripts See The Environment
`eval $(dependencyEnv)` is commonly used in these `scripts`. This `eval`
statement augments the environment for the duration of the named script, which
ensures that important binaries (such as `refmt`) are in the `PATH`.
> When the entire purpose of developer tools is to generate a binary (such as a
> compiler) to be included in your `PATH`, or produce a library whose path
> should be specified in an special environment variable, it's almost like the
> environment variable is the public API of that package. `dependencyEnv`
> allows your script to see the environment variables that your immediate
> dependencies wanted to publish as their public API. You can learn how
> packages can publish environment variables in the [dependency-env
> repo](https://github.com/npm-ml/dependency-env).
### Multiple Projects
You can have multiple clones/forks/builds of `ReasonProject` - one for each of
your projects. When you make changes, you can share the project easily with
anyone else because you are modelling all dependencies via `package.json`. If
also [using the global
environment](#editor-support), you may want to
designate one special `ReasonProject`, that is only used for augmenting the
global path.
### Creating Libraries
`ReasonProject` sets up your environment for building an application. We
haven't yet mentioned how to then share your work with other people *as* an
`npm` dependency itself. More coming soon.
## Troubleshooting
In general, if something goes wrong, try deleting the local `node_modules`
directory that was installed, and then try reinstalling using `npm install -f`
(to avoid using a stale cache). Then if that doesn't work, follow the following
steps to debug your specific failed dependency.
Also, remember to disable any system ocaml compilers that you have in your PATH.
For example, if you installed an OCaml compiler via opam, comment out the line in
your `~/.bashrc` or `~/.bash_profile` that source the opam environment,
and then open a new shell.
> Note: We will soon make it impossible for these kinds of conflicts to occur.
#### Debugging Failed Dependencies
When `npm install` fails to install one of your dependencies, it's typically
because a `postinstall` step of a package has failed. Read the logs to
determine which one is failing. `npm` will delete the directory of the failed
package so the failed install won't be in `node_modules`, but you can
usually try to reinstall it explicitly, and debug the installation. Suppose the
`@opam-alpha/qcheck` package failed to install. Let's recreate the failure so
we can debug it.
##### Do a dry run:
Let's see what an `npm install` for this package *would* install. The `--dry-run`
flag avoids actually installing anything.
```sh
npm install --dry-run @opam-alpha/qcheck
```
In my project, it says it would only need to install the following packages.
That's because all of the other ones must have already been installed in
`node_modules`.
```sh
# Output
test@1.0.0 /Users/jwalke/Desktop/tmp
└─┬ @opam-alpha/qcheck@0.4.0
└── qcheck-actual@0.4.0 (git://github.com/npm-opam/qcheck.git)
```
> Note: Sometimes it won't traverse `git` dependencies to find all the potentially installed
package. That's okay.
###### Install Source Without Building
So we want to install that now, but *without* executing the install scripts so we
pass the `--ignore-scripts` flag. Without that flag, it would fail when running
the scripts again, and then remove the package again!
```sh
npm install --ignore-scripts @opam-alpha/qcheck@0.4.0
```
This will just install the source code, and let us know what it actually installed.
###### Try The Build Manually, In Place
Now, make sure `npm` didn't do something weird with installing new versions of package
that didn't show up in the dry run, and make sure it installed things
as flat as possible in `node_modules`, as opposed to nesting `node_modules`
for compiled ocaml packages inside of other `node_modules`. Ideally, everything
is a flat list inside the `ReasonProject/node_modules` directory.
`cd` into the package that was failing to build correctly (it was actually the `qcheck-actual` package
in our case). Run the build command in `package.json`'s `postinstall` field by doing `npm run postinstall`.
```sh
cd node_modules/qcheck-actual
npm run postinstall
```
Now the package should fail as it did when you tried to install your top level project,
but without removing the packages, so you can debug the issue, fix it, then try rebuilding
again. Usually you need to reconfigure the problematic package, or fix the build script.
Fix it, and push an update for the package.
Finally, once you've pushed a fix to the package for the issue, `rm`
the entire project's `node_modules` directory and re-run `npm install`
from the top again. This just makes sure you've got everything
nice and clean as if you installed it for the first time.
```
npm run whereisocamlmerlin
```
</script>
<!-- Initializer -->
<script>
Flatdoc.run({
fetcher: function(callback) {
callback(null, document.getElementById('markdown').innerHTML);
},
highlight: function (code, value) {
return (value === 'reason') ? hljs.highlight('reason', code).value : hljs.highlight(value, code).value;
},
});
</script>
<!-- Meta -->
<meta property="og:image" content="./images/CubeRed598_614.png" />
<meta property="og:image:secure_url" content="./images/CubeRed598_614.png" />
<meta property="og:image:type" content="image/jpeg" />
<meta property="og:image:width" content="1196" />
<meta property="og:image:height" content="1228" />
<meta content="Reason Project: Build Reason Projects Rapidly" name="description">
<meta content="Reason Project: Build Reason Projects Rapidly" property="og:description">
<meta content="http://facebook.github.io/reason/images/logo.png" property="og:image">
</head>
<body role='flatdoc' class='big-h3 large-brief'>
<div class='title-area title-card'>
<div class='in'>
<img src="images/logo.png" style="max-width:598px; width:80%; padding-left:10%; padding-right:10%; -webkit-user-select:none; cursor:default"></img>
</div>
</div>
<div class='header'>
<div class='left'>
<h1><a href='index.html'>Reason Project</a></h1>
<ul>
<li><a href='https://github.com/reasonml/ReasonProject'>GitHub</a></li>
</ul>
</div>
</div>
<div class='content-root'>
<div class='menubar'>
<div class='menu section' role='flatdoc-menu'></div>
</div>
<div role='flatdoc-content' class='content'></div>
</div>
</body>
</html>