mirror of
https://github.com/fluencelabs/js-libp2p-noise
synced 2025-04-25 12:02:32 +00:00
Revert "Replace bcrypto with standalone libraries"
This commit is contained in:
parent
4506936456
commit
7b11f5a3ab
20
package.json
20
package.json
@ -20,7 +20,6 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "rm -rf lib && rm -rf dist",
|
"prebuild": "rm -rf lib && rm -rf dist",
|
||||||
"build": "yarn run build:node && yarn run build:web && yarn run build:types",
|
"build": "yarn run build:node && yarn run build:web && yarn run build:types",
|
||||||
"bundle": "webpack --config webpack.bundle.config.js",
|
|
||||||
"build:node": "babel --no-babelrc --config-file ./babel.config.json src --copy-files -x .ts -d dist --source-maps",
|
"build:node": "babel --no-babelrc --config-file ./babel.config.json src --copy-files -x .ts -d dist --source-maps",
|
||||||
"build:web": "babel --no-babelrc --config-file ./babel.web.config.json src --copy-files -x .ts -d lib --source-maps",
|
"build:web": "babel --no-babelrc --config-file ./babel.web.config.json src --copy-files -x .ts -d lib --source-maps",
|
||||||
"build:types": "tsc --declaration --outDir dist --emitDeclarationOnly",
|
"build:types": "tsc --declaration --outDir dist --emitDeclarationOnly",
|
||||||
@ -48,7 +47,6 @@
|
|||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.6.0",
|
"@typescript-eslint/eslint-plugin": "^2.6.0",
|
||||||
"@typescript-eslint/parser": "^2.6.0",
|
"@typescript-eslint/parser": "^2.6.0",
|
||||||
"babel-loader": "^8.1.0",
|
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"eslint": "^6.6.0",
|
"eslint": "^6.6.0",
|
||||||
"karma": "^4.4.1",
|
"karma": "^4.4.1",
|
||||||
@ -62,27 +60,21 @@
|
|||||||
"sinon": "^8.1.0",
|
"sinon": "^8.1.0",
|
||||||
"ts-loader": "^6.2.1",
|
"ts-loader": "^6.2.1",
|
||||||
"typescript": "^3.6.4",
|
"typescript": "^3.6.4",
|
||||||
"webpack": "^4.41.5",
|
"webpack": "^4.41.5"
|
||||||
"webpack-bundle-analyzer": "^3.6.1",
|
|
||||||
"webpack-cli": "^3.3.11"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aead-js": "^0.1.0",
|
"@types/bn.js": "^4.11.6",
|
||||||
|
"bcrypto": "5.1.0",
|
||||||
|
"bn.js": "^5.0.0",
|
||||||
"buffer": "^5.4.3",
|
"buffer": "^5.4.3",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"futoin-hkdf": "^1.3.2",
|
|
||||||
"hash.js": "^1.1.7",
|
|
||||||
"it-buffer": "^0.1.1",
|
"it-buffer": "^0.1.1",
|
||||||
"it-length-prefixed": "^3.0.0",
|
"it-length-prefixed": "^3.0.0",
|
||||||
"it-pair": "^1.0.0",
|
"it-pair": "^1.0.0",
|
||||||
"it-pb-rpc": "^0.1.8",
|
"it-pb-rpc": "^0.1.8",
|
||||||
"it-pipe": "^1.1.0",
|
"it-pipe": "^1.1.0",
|
||||||
"libp2p-crypto": "^0.17.6",
|
"libp2p-crypto": "^0.17.1",
|
||||||
"peer-id": "^0.13.5",
|
"peer-id": "^0.13.5",
|
||||||
"protobufjs": "6.8.8",
|
"protobufjs": "6.8.8"
|
||||||
"tweetnacl": "^1.0.1"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"bn.js": "4.4.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {Buffer} from 'buffer';
|
import BN from 'bn.js';
|
||||||
|
import { Buffer } from 'buffer';
|
||||||
|
|
||||||
export type bytes = Buffer;
|
export type bytes = Buffer;
|
||||||
export type bytes32 = Buffer;
|
export type bytes32 = Buffer;
|
||||||
export type bytes16 = Buffer;
|
export type bytes16 = Buffer;
|
||||||
|
|
||||||
export type uint32 = number;
|
export type uint32 = number;
|
||||||
export type uint64 = number;
|
export type uint64 = BN;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import {Buffer} from "buffer";
|
import {Buffer} from "buffer";
|
||||||
import hash from 'hash.js';
|
import { AEAD, x25519, SHA256 } from 'bcrypto';
|
||||||
import {box} from 'tweetnacl';
|
|
||||||
import {AEAD} from 'aead-js';
|
|
||||||
|
|
||||||
import {bytes, bytes32, uint32} from "../@types/basic";
|
import {bytes, bytes32, uint32} from "../@types/basic";
|
||||||
import {CipherState, MessageBuffer, SymmetricState} from "../@types/handshake";
|
import {CipherState, MessageBuffer, SymmetricState} from "../@types/handshake";
|
||||||
@ -106,8 +104,10 @@ export abstract class AbstractHandshake {
|
|||||||
|
|
||||||
protected dh(privateKey: bytes32, publicKey: bytes32): bytes32 {
|
protected dh(privateKey: bytes32, publicKey: bytes32): bytes32 {
|
||||||
try {
|
try {
|
||||||
const sharedKey = box.before(publicKey, privateKey)
|
const derived = x25519.derive(publicKey, privateKey);
|
||||||
return Buffer.from(sharedKey.buffer, sharedKey.byteOffset, sharedKey.length);
|
const result = Buffer.alloc(32);
|
||||||
|
derived.copy(result);
|
||||||
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger(e.message);
|
logger(e.message);
|
||||||
return Buffer.alloc(32);
|
return Buffer.alloc(32);
|
||||||
@ -119,8 +119,7 @@ export abstract class AbstractHandshake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getHash(a: bytes, b: bytes): bytes32 {
|
protected getHash(a: bytes, b: bytes): bytes32 {
|
||||||
const hashValue = hash.sha256().update(Buffer.from([...a, ...b])).digest();
|
return SHA256.digest(Buffer.from([...a, ...b]));
|
||||||
return Buffer.from(hashValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected mixKey(ss: SymmetricState, ikm: bytes32): void {
|
protected mixKey(ss: SymmetricState, ikm: bytes32): void {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import {Buffer} from "buffer";
|
import {Buffer} from "buffer";
|
||||||
|
import BN from "bn.js";
|
||||||
|
|
||||||
import {CipherState, HandshakeState, MessageBuffer, NoiseSession} from "../@types/handshake";
|
import {CipherState, HandshakeState, MessageBuffer, NoiseSession} from "../@types/handshake";
|
||||||
import {bytes, bytes32} from "../@types/basic";
|
import {bytes, bytes32} from "../@types/basic";
|
||||||
import {generateKeypair, isValidPublicKey} from "../utils";
|
import {generateKeypair, isValidPublicKey} from "../utils";
|
||||||
@ -20,21 +22,21 @@ export class IK extends AbstractHandshake {
|
|||||||
return {
|
return {
|
||||||
hs,
|
hs,
|
||||||
i: initiator,
|
i: initiator,
|
||||||
mc: 0,
|
mc: new BN(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessage(session: NoiseSession, message: bytes): MessageBuffer {
|
public sendMessage(session: NoiseSession, message: bytes): MessageBuffer {
|
||||||
let messageBuffer: MessageBuffer;
|
let messageBuffer: MessageBuffer;
|
||||||
if (session.mc === 0) {
|
if (session.mc.eqn(0)) {
|
||||||
messageBuffer = this.writeMessageA(session.hs, message);
|
messageBuffer = this.writeMessageA(session.hs, message);
|
||||||
} else if (session.mc === 1) {
|
} else if (session.mc.eqn(1)) {
|
||||||
const { messageBuffer: mb, h, cs1, cs2 } = this.writeMessageB(session.hs, message);
|
const { messageBuffer: mb, h, cs1, cs2 } = this.writeMessageB(session.hs, message);
|
||||||
messageBuffer = mb;
|
messageBuffer = mb;
|
||||||
session.h = h;
|
session.h = h;
|
||||||
session.cs1 = cs1;
|
session.cs1 = cs1;
|
||||||
session.cs2 = cs2;
|
session.cs2 = cs2;
|
||||||
} else if (session.mc > 1) {
|
} else if (session.mc.gtn(1)) {
|
||||||
if (session.i) {
|
if (session.i) {
|
||||||
if (!session.cs1) {
|
if (!session.cs1) {
|
||||||
throw new Error("CS1 (cipher state) is not defined")
|
throw new Error("CS1 (cipher state) is not defined")
|
||||||
@ -52,16 +54,16 @@ export class IK extends AbstractHandshake {
|
|||||||
throw new Error("Session invalid.")
|
throw new Error("Session invalid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.mc++;
|
session.mc = session.mc.add(new BN(1));
|
||||||
return messageBuffer;
|
return messageBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} {
|
public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} {
|
||||||
let plaintext = Buffer.alloc(0), valid = false;
|
let plaintext = Buffer.alloc(0), valid = false;
|
||||||
if (session.mc === 0) {
|
if (session.mc.eqn(0)) {
|
||||||
({plaintext, valid} = this.readMessageA(session.hs, message));
|
({plaintext, valid} = this.readMessageA(session.hs, message));
|
||||||
}
|
}
|
||||||
if (session.mc === 1) {
|
if (session.mc.eqn(1)) {
|
||||||
const { plaintext: pt, valid: v, h, cs1, cs2 } = this.readMessageB(session.hs, message);
|
const { plaintext: pt, valid: v, h, cs1, cs2 } = this.readMessageB(session.hs, message);
|
||||||
plaintext = pt;
|
plaintext = pt;
|
||||||
valid = v;
|
valid = v;
|
||||||
@ -69,7 +71,7 @@ export class IK extends AbstractHandshake {
|
|||||||
session.cs1 = cs1;
|
session.cs1 = cs1;
|
||||||
session.cs2 = cs2;
|
session.cs2 = cs2;
|
||||||
}
|
}
|
||||||
session.mc++;
|
session.mc = session.mc.add(new BN(1));
|
||||||
return {plaintext, valid};
|
return {plaintext, valid};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { Buffer } from 'buffer';
|
import { Buffer } from 'buffer';
|
||||||
|
import BN from 'bn.js';
|
||||||
|
|
||||||
import { bytes32, bytes } from '../@types/basic'
|
import { bytes32, bytes } from '../@types/basic'
|
||||||
import { KeyPair } from '../@types/libp2p'
|
import { KeyPair } from '../@types/libp2p'
|
||||||
import {generateKeypair, isValidPublicKey} from '../utils';
|
import {generateKeypair, isValidPublicKey} from '../utils';
|
||||||
@ -127,23 +129,23 @@ export class XX extends AbstractHandshake {
|
|||||||
return {
|
return {
|
||||||
hs,
|
hs,
|
||||||
i: initiator,
|
i: initiator,
|
||||||
mc: 0,
|
mc: new BN(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessage(session: NoiseSession, message: bytes, ephemeral?: KeyPair): MessageBuffer {
|
public sendMessage(session: NoiseSession, message: bytes, ephemeral?: KeyPair): MessageBuffer {
|
||||||
let messageBuffer: MessageBuffer;
|
let messageBuffer: MessageBuffer;
|
||||||
if (session.mc === 0) {
|
if (session.mc.eqn(0)) {
|
||||||
messageBuffer = this.writeMessageA(session.hs, message, ephemeral);
|
messageBuffer = this.writeMessageA(session.hs, message, ephemeral);
|
||||||
} else if (session.mc === 1) {
|
} else if (session.mc.eqn(1)) {
|
||||||
messageBuffer = this.writeMessageB(session.hs, message);
|
messageBuffer = this.writeMessageB(session.hs, message);
|
||||||
} else if (session.mc === 2) {
|
} else if (session.mc.eqn(2)) {
|
||||||
const { h, messageBuffer: resultingBuffer, cs1, cs2 } = this.writeMessageC(session.hs, message);
|
const { h, messageBuffer: resultingBuffer, cs1, cs2 } = this.writeMessageC(session.hs, message);
|
||||||
messageBuffer = resultingBuffer;
|
messageBuffer = resultingBuffer;
|
||||||
session.h = h;
|
session.h = h;
|
||||||
session.cs1 = cs1;
|
session.cs1 = cs1;
|
||||||
session.cs2 = cs2;
|
session.cs2 = cs2;
|
||||||
} else if (session.mc > 2) {
|
} else if (session.mc.gtn(2)) {
|
||||||
if (session.i) {
|
if (session.i) {
|
||||||
if (!session.cs1) {
|
if (!session.cs1) {
|
||||||
throw new Error("CS1 (cipher state) is not defined")
|
throw new Error("CS1 (cipher state) is not defined")
|
||||||
@ -161,18 +163,18 @@ export class XX extends AbstractHandshake {
|
|||||||
throw new Error("Session invalid.")
|
throw new Error("Session invalid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.mc++;
|
session.mc = session.mc.add(new BN(1));
|
||||||
return messageBuffer;
|
return messageBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} {
|
public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} {
|
||||||
let plaintext: bytes = Buffer.alloc(0);
|
let plaintext: bytes = Buffer.alloc(0);
|
||||||
let valid = false;
|
let valid = false;
|
||||||
if (session.mc === 0) {
|
if (session.mc.eqn(0)) {
|
||||||
({plaintext, valid} = this.readMessageA(session.hs, message));
|
({plaintext, valid} = this.readMessageA(session.hs, message));
|
||||||
} else if (session.mc === 1) {
|
} else if (session.mc.eqn(1)) {
|
||||||
({plaintext, valid} = this.readMessageB(session.hs, message));
|
({plaintext, valid} = this.readMessageB(session.hs, message));
|
||||||
} else if (session.mc === 2) {
|
} else if (session.mc.eqn(2)) {
|
||||||
const { h, plaintext: resultingPlaintext, valid: resultingValid, cs1, cs2 } = this.readMessageC(session.hs, message);
|
const { h, plaintext: resultingPlaintext, valid: resultingValid, cs1, cs2 } = this.readMessageC(session.hs, message);
|
||||||
plaintext = resultingPlaintext;
|
plaintext = resultingPlaintext;
|
||||||
valid = resultingValid;
|
valid = resultingValid;
|
||||||
@ -180,7 +182,7 @@ export class XX extends AbstractHandshake {
|
|||||||
session.cs1 = cs1;
|
session.cs1 = cs1;
|
||||||
session.cs2 = cs2;
|
session.cs2 = cs2;
|
||||||
}
|
}
|
||||||
session.mc++;
|
session.mc = session.mc.add(new BN(1));
|
||||||
return {plaintext, valid};
|
return {plaintext, valid};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {box} from 'tweetnacl';
|
import {x25519} from 'bcrypto';
|
||||||
import {Buffer} from "buffer";
|
import {Buffer} from "buffer";
|
||||||
import Wrap from 'it-pb-rpc';
|
import Wrap from 'it-pb-rpc';
|
||||||
import DuplexPair from 'it-pair/duplex';
|
import DuplexPair from 'it-pair/duplex';
|
||||||
@ -49,7 +49,7 @@ export class Noise implements INoiseConnection {
|
|||||||
this.useNoisePipes = false;
|
this.useNoisePipes = false;
|
||||||
|
|
||||||
if (staticNoiseKey) {
|
if (staticNoiseKey) {
|
||||||
const publicKey = Buffer.from(box.keyPair.fromSecretKey(staticNoiseKey).publicKey);
|
const publicKey = x25519.publicKeyCreate(staticNoiseKey);
|
||||||
this.staticKeys = {
|
this.staticKeys = {
|
||||||
privateKey: staticNoiseKey,
|
privateKey: staticNoiseKey,
|
||||||
publicKey,
|
publicKey,
|
||||||
|
24
src/utils.ts
24
src/utils.ts
@ -1,8 +1,7 @@
|
|||||||
import hkdf from 'futoin-hkdf';
|
import {HKDF, SHA256, x25519} from 'bcrypto';
|
||||||
import {box} from 'tweetnacl';
|
|
||||||
import {Buffer} from "buffer";
|
import {Buffer} from "buffer";
|
||||||
import PeerId from "peer-id";
|
import PeerId from "peer-id";
|
||||||
import {keys} from 'libp2p-crypto';
|
import * as crypto from 'libp2p-crypto';
|
||||||
import {KeyPair} from "./@types/libp2p";
|
import {KeyPair} from "./@types/libp2p";
|
||||||
import {bytes, bytes32} from "./@types/basic";
|
import {bytes, bytes32} from "./@types/basic";
|
||||||
import {Hkdf, INoisePayload} from "./@types/handshake";
|
import {Hkdf, INoisePayload} from "./@types/handshake";
|
||||||
@ -11,9 +10,8 @@ import {pb} from "./proto/payload";
|
|||||||
const NoiseHandshakePayloadProto = pb.NoiseHandshakePayload;
|
const NoiseHandshakePayloadProto = pb.NoiseHandshakePayload;
|
||||||
|
|
||||||
export function generateKeypair(): KeyPair {
|
export function generateKeypair(): KeyPair {
|
||||||
const keyPair = box.keyPair();
|
const privateKey = x25519.privateKeyGenerate();
|
||||||
const publicKey = Buffer.from(keyPair.publicKey);
|
const publicKey = x25519.publicKeyCreate(privateKey);
|
||||||
const privateKey = Buffer.from(keyPair.secretKey);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
publicKey,
|
publicKey,
|
||||||
@ -93,15 +91,17 @@ export async function verifySignedPayload(
|
|||||||
}
|
}
|
||||||
const generatedPayload = getHandshakePayload(noiseStaticKey);
|
const generatedPayload = getHandshakePayload(noiseStaticKey);
|
||||||
// Unmarshaling from PublicKey protobuf
|
// Unmarshaling from PublicKey protobuf
|
||||||
const publicKey = keys.unmarshalPublicKey(identityKey);
|
const publicKey = crypto.keys.unmarshalPublicKey(identityKey);
|
||||||
if (!publicKey.verify(generatedPayload, payload.identitySig as Buffer)) {
|
if (!publicKey.verify(generatedPayload, payload.identitySig)) {
|
||||||
throw new Error("Static key doesn't match to peer that signed payload!");
|
throw new Error("Static key doesn't match to peer that signed payload!");
|
||||||
}
|
}
|
||||||
return remotePeer;
|
return remotePeer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHkdf(ck: bytes32, ikm: bytes): Hkdf {
|
export function getHkdf(ck: bytes32, ikm: bytes): Hkdf {
|
||||||
const okm = hkdf(ikm, 96, {salt: ck, hash: 'SHA-256'});
|
const info = Buffer.alloc(0);
|
||||||
|
const prk = HKDF.extract(SHA256, ikm, ck);
|
||||||
|
const okm = HKDF.expand(SHA256, prk, info, 96);
|
||||||
|
|
||||||
const k1 = okm.slice(0, 32);
|
const k1 = okm.slice(0, 32);
|
||||||
const k2 = okm.slice(32, 64);
|
const k2 = okm.slice(32, 64);
|
||||||
@ -111,9 +111,5 @@ export function getHkdf(ck: bytes32, ikm: bytes): Hkdf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isValidPublicKey(pk: bytes): boolean {
|
export function isValidPublicKey(pk: bytes): boolean {
|
||||||
if(pk.length !== 32 || pk.equals(Buffer.alloc(32))){
|
return x25519.publicKeyVerify(pk.slice(0, 32));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ import DuplexPair from 'it-pair/duplex';
|
|||||||
import {Noise} from "../src";
|
import {Noise} from "../src";
|
||||||
import {createPeerIdsFromFixtures} from "./fixtures/peer";
|
import {createPeerIdsFromFixtures} from "./fixtures/peer";
|
||||||
import Wrap from "it-pb-rpc";
|
import Wrap from "it-pb-rpc";
|
||||||
|
import {random} from "bcrypto";
|
||||||
import sinon from "sinon";
|
import sinon from "sinon";
|
||||||
import {randomBytes} from 'libp2p-crypto';
|
|
||||||
import {XXHandshake} from "../src/handshake-xx";
|
import {XXHandshake} from "../src/handshake-xx";
|
||||||
import {createHandshakePayload, generateKeypair, getHandshakePayload, getPayload, signPayload} from "../src/utils";
|
import {createHandshakePayload, generateKeypair, getHandshakePayload, getPayload, signPayload} from "../src/utils";
|
||||||
import {decode0, decode2, encode1, uint16BEDecode, uint16BEEncode} from "../src/encoder";
|
import {decode0, decode2, encode1, uint16BEDecode, uint16BEEncode} from "../src/encoder";
|
||||||
@ -122,7 +122,7 @@ describe("Noise", () => {
|
|||||||
const wrappedInbound = Wrap(inbound.conn);
|
const wrappedInbound = Wrap(inbound.conn);
|
||||||
const wrappedOutbound = Wrap(outbound.conn);
|
const wrappedOutbound = Wrap(outbound.conn);
|
||||||
|
|
||||||
const largePlaintext = randomBytes(100000);
|
const largePlaintext = random.randomBytes(100000);
|
||||||
wrappedOutbound.writeLP(largePlaintext);
|
wrappedOutbound.writeLP(largePlaintext);
|
||||||
const response = await wrappedInbound.read(100000);
|
const response = await wrappedInbound.read(100000);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import {keys} from 'libp2p-crypto';
|
import * as crypto from 'libp2p-crypto';
|
||||||
import {KeyPair, PeerId} from "../src/@types/libp2p";
|
import {KeyPair, PeerId} from "../src/@types/libp2p";
|
||||||
|
|
||||||
export async function generateEd25519Keys() {
|
export async function generateEd25519Keys() {
|
||||||
return await keys.generateKeyPair('ed25519');
|
return await crypto.keys.generateKeyPair('ed25519');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getKeyPairFromPeerId(peerId: PeerId): KeyPair {
|
export function getKeyPairFromPeerId(peerId: PeerId): KeyPair {
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: "./src/index.ts",
|
|
||||||
mode: "production",
|
|
||||||
output: {
|
|
||||||
filename: "../bundle/bundle.js"
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
fs: "empty"
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: [".ts", ".js"],
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{test: /\.ts$/, exclude: [/node_modules/], use: {loader: "babel-loader", options: require("./babel.web.config")}}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new BundleAnalyzerPlugin()
|
|
||||||
]
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user