bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.72k stars 2.11k forks source link

how to browserify the complete bitcoinjs-lib? #965

Closed SuperHenkie closed 6 years ago

SuperHenkie commented 6 years ago

Previously I remember the install instructions for browserify contained something like browserify bitcoinjs-lib -s bitcoin > bitcoinjs.js to build a standalone version of bitcoinjs.

Nowadays the instructions contain instructions to create an index.js with a myFunction which does one particular thing (creating a random private key, in this case) and then exports that function.

How do I just export everything, i.e. create the entire bitcoinjs lib that I can include in a .html file just like before?

Perhaps a stupid question, in that case my apologies, but other than bitcoinjs I never used browserify for anything else and I'm not quite sure how this works.

dabura667 commented 6 years ago

browserify -r bitcoinjs-lib —standalone bitcoinjs | uglifyjs -c --mangle reserved=['BigInteger','ECPair','Point'] -o bitcoinjs.min.js

Make sure you have the most recent version installed otherwis you need to use uglify-es instead of uglify-js (both packages use the uglifyjs command, so don’t install both globally.)

SuperHenkie commented 6 years ago

@dabura667 Thanks, but the latest version of what? I think I have the lastest nodejs and npm.

However when I try the command you suggested I'm getting this error:

Error: Cannot find module '/Users/SuperHenkie/projects/bitcoinjs/bitcoinjs' from '/Users/SuperHenkie/projects/bitcoinjs'
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:55:21
    at load (/usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:69:43)
    at onex (/usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:92:31)
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:22:47
    at FSReqWrap.oncomplete (fs.js:166:21)

The same problem occurs if a Ieave out the uglifyjs part, and just do this:

browserify -r bitcoinjs-lib —standalone bitcoinjs -o bitcoinjs.js

junderw commented 6 years ago

if you're in the source repository cloned from github, make sure to install, and use . instead of the library name.

~/git $ git clone https://github.com/bitcoinjs/bitcoinjs-lib.git
~/git $ cd bitcoinjs-lib
~/git/bitcoinjs-lib $ git fetch --all
~/git/bitcoinjs-lib $ git checkout 8bd95bd49808c9eeba2b065ef6552c7a9d07963e
~/git/bitcoinjs-lib $ npm install
~/git/bitcoinjs-lib $ browserify -r . --standalone bitcoinjs | uglifyjs -c --mangle reserved=['BigInteger','ECPair','Point'] -o bitcoinjs-8bd95bd.min.js

Then load into html:

<script src="./js/bitcoinjs-8bd95bd.min.js"></script>

Then access the library from the global object bitcoinjs this can be changed by the word after --standalone

SuperHenkie commented 6 years ago

Thanks @junderw That seems to get rid of the error, however if I understand correctly I am now building a specific revision form the git repository.

Is there a way do to the same but take the latest official / stable version from npm? (also in the future I mean, whatever version or revision that may be at that time)

If I do npm install bitcoinjs-lib in an empty dir, create a new file "index.js" in there with this:

var bitcoin_js = require('bitcoinjs-lib')
module.exports = { bitcoin_js }

And then do browserify -r . --standalone bitcoinjs > bitcoinjs.js it seems to work as well. But I'm not fully sure what I'm doing there with that exports = { bitcoin_js } thing. Is my approach correct?

junderw commented 6 years ago

The file you made will need to be accessed by calling bitcoinjs.bitcoin_js since your index.js is exporting the imported bitcoinjs-lib as a key called bitcoin_js

{ bitcoin_js } is the same as { 'bitcoin_js': bitcoin_js } it's just a more recent syntax update.

junderw commented 6 years ago

module.exports = require('bitcoinjs-lib') is simpler

SuperHenkie commented 6 years ago

@junderw Great, yes, I understand what bitcoinjs.bitcoin_js does, and I like the simpler approach you added (the other approach seems just like a unnecessary dummy symbol).

I think I got it working now, however if I try an example like this: generate address from sha256 hash it doesn't know bigi. So I assumed I had to export that separately. I can get that working by using dummy symbols again (in the module.exports line in index.js) but just out of curiosity, is there also a syntax without those extra symbols?

Again thanks a lot, much appreciated.

junderw commented 6 years ago
var bitcoin_js = require('bitcoinjs-lib')
bitcoin_js.bigi = require('bigi')
bitcoin_js.Buffer = require('safe-buffer').Buffer
module.exports = bitcoin_js

This could help give you some extra tools to work with.

junderw commented 6 years ago

(There was a really bad bug with Buffer in older Node.JS versions... so just in case, use safe-buffer like I showed above)

SuperHenkie commented 6 years ago

Oh right, good one, thanks!

SuperHenkie commented 6 years ago

Another issue, I'm now trying to uglifyjs the result, but it leads to another error. Here's what I do:

  1. index.js contains:

    var bitcoin_js = require('bitcoinjs-lib')
    bitcoin_js.bigi = require('bigi')
    bitcoin_js.Buffer = require('safe-buffer').Buffer
    module.exports = bitcoin_js
  2. browserify -r . --standalone bitcoinjs > bitcoinjs.js works all right

  3. uglifyjs -c --mangle reserved=['BigInteger','ECPair','Point'] bitcoinjs.js > bitcoinjs.min.js gives this error:

Parse error at bitcoinjs.js:97,4
let ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
    ^

I assume this has to do with ES6 (in)compatibility. I also noticed that the project page mentions:

NOTE: This library tracks Node LTS features, if you need strict ES5, use --transform babelify in conjunction with your browserify step (using an es2015 preset).

Well yes I would prefer ES5. So I did npm install babelify and changed step 2 into browserify -r . --transform babelify --standalone bitcoinjs > bitcoinjs.js But that doesn't fix the error in step 3, I'm still getting that error about let ALPHABET = ...

Then I tried npm install --save-dev babelify babel-core babel-preset-es2015 and changed step 2 into browserify -r . --transform [ babelify --presets [ es2015 ] ] --standalone bitcoinjs > bitcoinjs.js but then still the same error appears in step 3.

I have no idea what I'm doing with that --save-dev stuff and the babel preset parameters, I just tried googling around. The description the project page seems to assume this is trivial but I'm really lost here.

I also tried the same with npm install uglify-js instead of uglifyjs (since I noticed it said "uglifyjs is deprecated - use uglify-js instead") but no improvement.

TL;DR = how do I browserify and uglify (minify) bitcoinjs-lib ?

junderw commented 6 years ago

Use github master instead of npm. Github master uses a newer version of bech32 that removed the let statements.

OR

(much easier) (uglify-es minifies ES6 perfectly) (uglify-es installs the binary uglifyjs, so the command is the same)

$ npm remove -g uglify-js uglifyjs
$ npm install -g uglify-es
$ browserify -r . --standalone bitcoinjs | uglifyjs -c --mangle reserved=['BigInteger','ECPair','Point'] -o bitcoinjs.min.js
SuperHenkie commented 6 years ago

Thank you so much again.. learned a lot here :+1:

dcousens commented 6 years ago

@SuperHenkie please don't use the bitcoinjs master branch, it isn't considered stable and could impact you unsafely later.

@junderw please don't recommend master branch, in theory, it could be OK, but in practice, it has hurt many developers and companies that weren't paying attention.

If you are thinking of using the master branch of this library in production, stop. Master is not stable; it is our development branch, and only tagged releases may be classified as stable.

Published bitcoinjs-lib@3.3.2, which has the bech32 version update that you needed.

:snowman_with_snow:

SuperHenkie commented 6 years ago

@dcousens I was aware of that, but thanks for pointing it out again explicitly, can't be too safe & certain 👍

I was actually using the easier solution from @junderw i.e. the npm version and uglify-es. Works like a charm.

And thanks for publishing 3.3.2, I just updated, I noticed the let statements are gone.

EvilJordan commented 6 years ago

Hey, @SuperHenkie, would you mind posting the exact steps you finally ended up using that worked for you?

SuperHenkie commented 6 years ago

@EvilJordan sure:

  1. Make sure nodejs and npm are up to date

  2. Create a new dir and from within that dir do npm install bitcoinjs-lib browserify uglify-es

  3. Create an index.js file in the same dir with this content:

var bitcoin_js = require('bitcoinjs-lib')
bitcoin_js.bigi = require('bigi')
bitcoin_js.Buffer = require('safe-buffer').Buffer
module.exports = bitcoin_js
  1. browserify -r . --standalone bitcoinjs > bitcoinjs.js

  2. uglifyjs -c --mangle reserved=['BigInteger','ECPair','Point'] bitcoinjs.js > bitcoinjs.min.js

This creates both the full bitcoinjs.js and minified bitcoinjs.min.js.

dcousens commented 6 years ago

@SuperHenkie out of interest (to help me improve this library), could you describe how you use bigi and why you felt necessary to export it?

SuperHenkie commented 6 years ago

@dcousens Sure, for example I use bigi to use raw 256-bit private keys and brainwallets, like this:

var passphrase = 'correct horse battery staple'
var keyPair = new bitcoin.ECPair(Bitcoin.bigi.fromBuffer(Bitcoin.crypto.sha256(passphrase)))

And all sorts of variants like this. Very useful imho.

dcousens commented 6 years ago

@SuperHenkie thanks for the reply, could you post what other variants you use?

junderw commented 6 years ago

In general, user determined brainwallets are bad, so don't do them... but if you want a format that wallets actually use, you can use bip39. They can then import the bip39 phrase into most wallets.

SuperHenkie commented 6 years ago

@dcousens For example it allows me to "implicitly store" private keys on my website in a secure way. Or actually not the private keys, but a long (>256bit) pseudorandom seed, which combined with a password (which is entered and processed only client side) I can use to deterministically regenerate the private key.

SuperHenkie commented 6 years ago

@junderw Good point and normally I fully agree, but I'm aware of the typical weakness in "human entropy" and it doesn't apply in my use case.

EvilJordan commented 4 years ago

Two years later, searching for this information and I find my own post in this thread. Convenient!

@SuperHenkie, thank you so much for those instructions. I just tried it again today, and I'm getting this error:

SyntaxError: Unexpected token (4:6) while parsing /development/node_modules/bitcoinjs-lib/src/ecpair.js while parsing file: /development/node_modules/bitcoinjs-lib/src/ecpair.js
    at DestroyableTransform.end [as _flush] (/opt/local/lib/node_modules/browserify/node_modules/insert-module-globals/index.js:96:21)
    at DestroyableTransform.<anonymous> (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_transform.js:115:49)
    at Object.onceWrapper (events.js:417:28)
    at DestroyableTransform.emit (events.js:311:20)
    at prefinish (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:503:12)
    at finishMaybe (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:511:7)
    at endWritable (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:523:3)
    at DestroyableTransform.Writable.end (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:493:41)
    at DestroyableTransform.onend (/opt/local/lib/node_modules/browserify/node_modules/readable-stream/lib/_stream_readable.js:504:10)
    at Object.onceWrapper (events.js:417:28)

ecpair.js at 4:6 looks ok to me...:

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const NETWORKS = require('./networks');
const types = require('./types');
const ecc = require('tiny-secp256k1');
const randomBytes = require('randombytes');
const typeforce = require('typeforce');
const wif = require('wif');

This is latest node/npm (and with an older version [11.something]) as well. Any ideas?

junderw commented 4 years ago

just tried it with:

and

node v13.12.0 or node v11.15.0 (I tried both)

No errors.

EvilJordan commented 4 years ago

Thanks for testing! Something must be seriously hosed on my system...

junderw commented 4 years ago

Try spinning up one of the node v12 containers from docker hub and see if you can't get it to work in there.

Usually that's what I do when I want to make sure it's not my system.

EvilJordan commented 4 years ago

Not the most informative, but I completely removed browserify from my system, reinstalled it, and now everything works ¯\_(ツ)_/¯

Thanks for your help, @junderw!

junderw commented 4 years ago

it happens. :rofl:

xloem commented 4 years ago

It would be great for someone to provide browserify bundles so people can check against common integrity checksums.

junderw commented 4 years ago

This has been discussed at length #1220 #314

Please do not advertise any minified js files on this repository.