mirror of
https://github.com/quantum5/correcthorsebatterystaple.git
synced 2025-04-24 10:11:57 -04:00
Add password generator proper and small word list
This commit is contained in:
parent
ab4b249aa6
commit
7c2bcc3f9b
34
package-lock.json
generated
34
package-lock.json
generated
|
@ -523,7 +523,8 @@
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"base": {
|
"base": {
|
||||||
"version": "0.11.2",
|
"version": "0.11.2",
|
||||||
|
@ -681,6 +682,7 @@
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
|
@ -1142,7 +1144,8 @@
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"concat-stream": {
|
"concat-stream": {
|
||||||
"version": "1.6.2",
|
"version": "1.6.2",
|
||||||
|
@ -1227,6 +1230,11 @@
|
||||||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"core-js": {
|
||||||
|
"version": "2.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||||
|
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
|
||||||
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
|
@ -2272,6 +2280,11 @@
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"form-serializer": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-serializer/-/form-serializer-2.5.0.tgz",
|
||||||
|
"integrity": "sha1-yuovrLwbzuf2VdkTZwcTPz+staM="
|
||||||
|
},
|
||||||
"forwarded": {
|
"forwarded": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
|
@ -2318,7 +2331,8 @@
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
|
@ -2929,6 +2943,7 @@
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
|
@ -3444,6 +3459,7 @@
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
|
@ -3452,7 +3468,8 @@
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"internal-ip": {
|
"internal-ip": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
|
@ -4178,6 +4195,7 @@
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
|
@ -4665,6 +4683,7 @@
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
|
@ -4853,7 +4872,8 @@
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-is-inside": {
|
"path-is-inside": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -5583,6 +5603,7 @@
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.0.5"
|
"glob": "^7.0.5"
|
||||||
}
|
}
|
||||||
|
@ -7323,7 +7344,8 @@
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"xregexp": {
|
"xregexp": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^4.1.3",
|
"bootstrap": "^4.1.3",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
|
"core-js": "^2.5.7",
|
||||||
|
"form-serializer": "^2.5.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
"octicons": "^8.1.3",
|
"octicons": "^8.1.3",
|
||||||
"popper.js": "^1.14.5"
|
"popper.js": "^1.14.5"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
import './app.scss'
|
import './app.scss'
|
||||||
import './clipboard'
|
import './clipboard'
|
||||||
import './navbar'
|
import './navbar'
|
||||||
|
import './ui'
|
||||||
|
|
|
@ -31,4 +31,8 @@ body {
|
||||||
|
|
||||||
#password-bits {
|
#password-bits {
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
|
|
||||||
|
.bg-warning {
|
||||||
|
color: $body-color;
|
||||||
|
}
|
||||||
}
|
}
|
62
src/generator.js
Normal file
62
src/generator.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import words from './words'
|
||||||
|
|
||||||
|
const digits = '0123456789'
|
||||||
|
const symbols = '`~!@#$%^&*()_+-=,./<>?;:|'
|
||||||
|
|
||||||
|
export function getWordList (name) {
|
||||||
|
if (['small'].includes(name)) {
|
||||||
|
return words[name]
|
||||||
|
}
|
||||||
|
throw new Error(`Invalid word list: ${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWords (list, indices) {
|
||||||
|
return Array.from(indices).map(index => list[index % list.length])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function capitalize (string) {
|
||||||
|
return string[0].toUpperCase() + string.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickWords (list, number) {
|
||||||
|
const array = new Uint16Array(number)
|
||||||
|
window.crypto.getRandomValues(array)
|
||||||
|
return getWords(list, array)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickChar (options) {
|
||||||
|
const array = new Uint32Array(1)
|
||||||
|
window.crypto.getRandomValues(array)
|
||||||
|
return options[array[0] % options.length]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generate (options) {
|
||||||
|
let words = pickWords(getWordList(options.list), options.count)
|
||||||
|
|
||||||
|
if (options.capitalize) {
|
||||||
|
words = words.map(capitalize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.symbol) {
|
||||||
|
words.push(pickChar(symbols))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.digit) {
|
||||||
|
words.push(pickChar(digits))
|
||||||
|
}
|
||||||
|
|
||||||
|
return words.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function lengthBits (list) {
|
||||||
|
return Math.log2(list.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeBits (options) {
|
||||||
|
const wordBits = lengthBits(getWordList(options.list))
|
||||||
|
const capsBits = options.capitalize ? 1 : 0
|
||||||
|
const symbolBits = options.symbol ? lengthBits(symbols) : 0
|
||||||
|
const digitBits = options.digit ? lengthBits(digits) : 0
|
||||||
|
|
||||||
|
return wordBits * options.count + capsBits + symbolBits + digitBits
|
||||||
|
}
|
|
@ -32,31 +32,31 @@
|
||||||
<div class="jumbotron py-4">
|
<div class="jumbotron py-4">
|
||||||
<p class="lead">This is a truly secure password generator that generates easy-to-remember passwords.</p>
|
<p class="lead">This is a truly secure password generator that generates easy-to-remember passwords.</p>
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
<form>
|
<div class="input-group mb-3">
|
||||||
<div class="input-group mb-3">
|
<input id="generated-password" class="form-control form-control-lg text-monospace" type="text"
|
||||||
<input id="generated-password" class="form-control" type="text"
|
placeholder="Click the Generate button to generate a new password">
|
||||||
placeholder="Click the Generate button to generate a new password">
|
<div class="input-group-append">
|
||||||
<div class="input-group-append">
|
<button class="btn btn-success copy" type="button" id="copy-password"
|
||||||
<button class="btn btn-success copy" type="button" id="copy-password"
|
data-clipboard-target="#generated-password">
|
||||||
data-clipboard-target="#generated-password">
|
${require('octicons').clippy.toSVG({ height: 20 })}
|
||||||
${require('octicons').clippy.toSVG({ height: 20 })}
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="progress my-3" id="password-bits">
|
<div class="progress my-3" id="password-bits">
|
||||||
<div class="progress-bar" role="progressbar" style="width: 44%"
|
<div class="progress-bar" role="progressbar" style="width: 44%"
|
||||||
aria-valuenow="44" aria-valuemin="0" aria-valuemax="100">44 bits
|
aria-valuenow="44" aria-valuemin="0" aria-valuemax="100">44 bits
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="options-form">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="word-list" class="col-sm-2 col-form-label">Word List</label>
|
<label for="word-list" class="col-sm-2 col-form-label">Word List</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<select id="word-list" class="form-control custom-select">
|
<select id="word-list" class="form-control custom-select" name="list">
|
||||||
<option value="small">2048 words (11 bits/word)</option>
|
<option value="small">2048 words (11 bits/word)</option>
|
||||||
<option value="medium">4096 words (12 bits/word)</option>
|
<option value="medium" disabled>4096 words (12 bits/word)</option>
|
||||||
<option value="large">8192 words (13 bits/word)</option>
|
<option value="large" disabled>8192 words (13 bits/word)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="word-count" class="col-sm-2 col-form-label">Word Count</label>
|
<label for="word-count" class="col-sm-2 col-form-label">Word Count</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input id="word-count" class="form-control" type="number" value="4">
|
<input id="word-count" class="form-control" type="number" name="count" value="5" min="1">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -72,15 +72,15 @@
|
||||||
<div class="pt-0 col-sm-2 col-form-label">Options</div>
|
<div class="pt-0 col-sm-2 col-form-label">Options</div>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="use-capitalize">
|
<input class="form-check-input" type="checkbox" id="use-capitalize" name="capitalize">
|
||||||
<label for="use-capitalize">Capitalize the first letter</label>
|
<label for="use-capitalize">Capitalize the first letter</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="use-symbol">
|
<input class="form-check-input" type="checkbox" id="use-symbol" name="symbol">
|
||||||
<label for="use-symbol">Add a symbol</label>
|
<label for="use-symbol">Add a symbol</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="use-digit">
|
<input class="form-check-input" type="checkbox" id="use-digit" name="digit">
|
||||||
<label for="use-digit">Add a digit</label>
|
<label for="use-digit">Add a digit</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
50
src/ui.js
Normal file
50
src/ui.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import $ from 'jquery/dist/jquery'
|
||||||
|
import 'form-serializer/jquery.serialize-object'
|
||||||
|
|
||||||
|
import { generate, computeBits } from './generator'
|
||||||
|
|
||||||
|
$(() => {
|
||||||
|
const $options = $('#options-form')
|
||||||
|
const $output = $('#generated-password')
|
||||||
|
const $bits = $('#password-bits').find('div')
|
||||||
|
|
||||||
|
$('#run-generator').click(() => {
|
||||||
|
const options = $options.serializeObject()
|
||||||
|
$output.val(generate(options))
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
const classes = 'bg-danger bg-warning bg-info bg-success'
|
||||||
|
|
||||||
|
function bitClass (bits) {
|
||||||
|
if (bits < 44) {
|
||||||
|
return 'bg-danger'
|
||||||
|
} else if (bits < 64) {
|
||||||
|
return 'bg-warning'
|
||||||
|
} else if (bits < 80) {
|
||||||
|
return 'bg-info'
|
||||||
|
} else {
|
||||||
|
return 'bg-success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bitRound (value) {
|
||||||
|
const rounded = Math.round(value)
|
||||||
|
return rounded === value ? value : `≈ ${rounded}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBitMeter () {
|
||||||
|
const options = $options.serializeObject()
|
||||||
|
const bits = computeBits(options)
|
||||||
|
const maxBits = 96
|
||||||
|
$bits
|
||||||
|
.removeClass(classes)
|
||||||
|
.addClass(bitClass(bits))
|
||||||
|
.text(`${bitRound(bits)} bits`)
|
||||||
|
.css('width', `${bits / maxBits * 100}%`)
|
||||||
|
}
|
||||||
|
|
||||||
|
$options.find('select, input').change(updateBitMeter)
|
||||||
|
$options.find('input[type=nubmer]').on('input', updateBitMeter)
|
||||||
|
updateBitMeter()
|
||||||
|
})
|
2050
src/words/2048.js
Normal file
2050
src/words/2048.js
Normal file
File diff suppressed because it is too large
Load diff
5
src/words/index.js
Normal file
5
src/words/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import small from './2048'
|
||||||
|
|
||||||
|
console.assert(small.length === 2048)
|
||||||
|
|
||||||
|
export default { small }
|
|
@ -2,7 +2,11 @@ const path = require('path')
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/app.js',
|
entry: [
|
||||||
|
'core-js/fn/array/from',
|
||||||
|
'core-js/fn/array/includes',
|
||||||
|
'./src/app.js'
|
||||||
|
],
|
||||||
mode: process.env.NODE_ENV || 'development',
|
mode: process.env.NODE_ENV || 'development',
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].[contenthash].js',
|
filename: '[name].[contenthash].js',
|
||||||
|
|
Loading…
Reference in a new issue