mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-17 21:16:34 +02:00
improve Babel and webpack configurations --> reduce JS bundle size (#670)
* simplify babel config * fix Cypress VSCode checks * introduce webpack base config * fix flacky cypress test * fix class properties definition * fix default export * upgrade affected deps, decrease bundlesize * run ESLint only on changed files
This commit is contained in:
parent
00bf028904
commit
6848970fd9
10
.babelrc
10
.babelrc
|
@ -1,11 +1,3 @@
|
||||||
{
|
{
|
||||||
"presets": [
|
"presets": [["@babel/preset-env", { "loose": true }]]
|
||||||
"@babel/preset-env"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"@babel/plugin-transform-modules-commonjs",
|
|
||||||
["@babel/plugin-transform-spread", {
|
|
||||||
"loose": true
|
|
||||||
}]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
5
.github/workflows/lint.yml
vendored
5
.github/workflows/lint.yml
vendored
|
@ -25,4 +25,7 @@ jobs:
|
||||||
HUSKY_SKIP_INSTALL: true
|
HUSKY_SKIP_INSTALL: true
|
||||||
|
|
||||||
- name: run eslint
|
- name: run eslint
|
||||||
run: npx eslint src/scripts
|
run: |
|
||||||
|
CHANGED_JS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.js$' | grep -v json)
|
||||||
|
echo $CHANGED_JS
|
||||||
|
node node_modules/eslint/bin/eslint.js $CHANGED_JS
|
||||||
|
|
36
README.md
36
README.md
|
@ -1,5 +1,5 @@
|
||||||
# Choices.js [![Actions Status](https://github.com/jshjohnson/Choices/workflows/Unit%20Tests/badge.svg)](https://github.com/jshjohnson/Choices/actions) [![npm](https://img.shields.io/npm/v/choices.js.svg)](https://www.npmjs.com/package/choices.js) [![codebeat badge](https://codebeat.co/badges/55120150-5866-42d8-8010-6aaaff5d3fa1)](https://codebeat.co/projects/github-com-jshjohnson-choices-master)
|
# Choices.js [![Actions Status](https://github.com/jshjohnson/Choices/workflows/Unit%20Tests/badge.svg)](https://github.com/jshjohnson/Choices/actions) [![npm](https://img.shields.io/npm/v/choices.js.svg)](https://www.npmjs.com/package/choices.js) [![codebeat badge](https://codebeat.co/badges/55120150-5866-42d8-8010-6aaaff5d3fa1)](https://codebeat.co/projects/github-com-jshjohnson-choices-master)
|
||||||
A vanilla, lightweight (~22kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.
|
A vanilla, lightweight (~19kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.
|
||||||
|
|
||||||
[Demo](https://joshuajohnson.co.uk/Choices/)
|
[Demo](https://joshuajohnson.co.uk/Choices/)
|
||||||
|
|
||||||
|
@ -153,11 +153,11 @@ will be returned. If you target one element, that instance will be returned.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Terminology
|
## Terminology
|
||||||
| Word | Definition |
|
| Word | Definition |
|
||||||
| ------ | ---------- |
|
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| Choice | A choice is a value a user can select. A choice would be equivalent to the `<option></option>` element within a select input. |
|
| Choice | A choice is a value a user can select. A choice would be equivalent to the `<option></option>` element within a select input. |
|
||||||
| Group | A group is a collection of choices. A group should be seen as equivalent to a `<optgroup></optgroup>` element within a select input.|
|
| Group | A group is a collection of choices. A group should be seen as equivalent to a `<optgroup></optgroup>` element within a select input. |
|
||||||
| Item | An item is an inputted value (text input) or a selected choice (select element). In the context of a select element, an item is equivalent to a selected option element: `<option value="Hello" selected></option>` whereas in the context of a text input an item is equivalent to `<input type="text" value="Hello">`|
|
| Item | An item is an inputted value (text input) or a selected choice (select element). In the context of a select element, an item is equivalent to a selected option element: `<option value="Hello" selected></option>` whereas in the context of a text input an item is equivalent to `<input type="text" value="Hello">` |
|
||||||
|
|
||||||
|
|
||||||
## Configuration options
|
## Configuration options
|
||||||
|
@ -946,18 +946,18 @@ To setup a local environment: clone this repo, navigate into it's directory in a
|
||||||
```npm install```
|
```npm install```
|
||||||
|
|
||||||
### NPM tasks
|
### NPM tasks
|
||||||
| Task | Usage |
|
| Task | Usage |
|
||||||
| -------------------- | ------------------------------------------------------------ |
|
| ------------------------- | ------------------------------------------------------------ |
|
||||||
| `npm run start` | Fire up local server for development |
|
| `npm run start` | Fire up local server for development |
|
||||||
| `npm run test:unit` | Run sequence of tests once |
|
| `npm run test:unit` | Run sequence of tests once |
|
||||||
| `npm run test:unit:watch` | Fire up test server and re-test on file change |
|
| `npm run test:unit:watch` | Fire up test server and re-test on file change |
|
||||||
| `npm run test:e2e` | Run sequence of e2e tests (with local server) |
|
| `npm run test:e2e` | Run sequence of e2e tests (with local server) |
|
||||||
| `npm run test` | Run both unit and e2e tests |
|
| `npm run test` | Run both unit and e2e tests |
|
||||||
| `npm run cypress:open` | Run Cypress e2e tests (GUI) |
|
| `npm run cypress:open` | Run Cypress e2e tests (GUI) |
|
||||||
| `npm run cypress:run` | Run Cypress e2e tests (CLI) |
|
| `npm run cypress:run` | Run Cypress e2e tests (CLI) |
|
||||||
| `npm run js:build` | Compile Choices to an uglified JavaScript file |
|
| `npm run js:build` | Compile Choices to an uglified JavaScript file |
|
||||||
| `npm run css:watch` | Watch SCSS files for changes. On a change, run build process |
|
| `npm run css:watch` | Watch SCSS files for changes. On a change, run build process |
|
||||||
| `npm run css:build` | Compile, minify and prefix SCSS files to CSS |
|
| `npm run css:build` | Compile, minify and prefix SCSS files to CSS |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
MIT License
|
MIT License
|
||||||
|
|
|
@ -755,7 +755,7 @@ describe('Choices - select multiple', () => {
|
||||||
describe('within form', () => {
|
describe('within form', () => {
|
||||||
describe('selecting choice', () => {
|
describe('selecting choice', () => {
|
||||||
describe('on enter key', () => {
|
describe('on enter key', () => {
|
||||||
it('does not submit form', () => {
|
it('selects choice', () => {
|
||||||
cy.get('[data-test-hook=within-form] form').then($form => {
|
cy.get('[data-test-hook=within-form] form').then($form => {
|
||||||
$form.submit(() => {
|
$form.submit(() => {
|
||||||
// this will fail the test if the form submits
|
// this will fail the test if the form submits
|
||||||
|
@ -765,7 +765,7 @@ describe('Choices - select multiple', () => {
|
||||||
|
|
||||||
cy.get('[data-test-hook=within-form]')
|
cy.get('[data-test-hook=within-form]')
|
||||||
.find('.choices__input--cloned')
|
.find('.choices__input--cloned')
|
||||||
.focus()
|
.click()
|
||||||
.type('{enter}');
|
.type('{enter}');
|
||||||
|
|
||||||
cy.get('[data-test-hook=within-form]')
|
cy.get('[data-test-hook=within-form]')
|
||||||
|
|
9
jsconfig.json
Normal file
9
jsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"baseUrl": "../node_modules",
|
||||||
|
"target": "es2020",
|
||||||
|
"lib": ["es5", "dom"],
|
||||||
|
"types": ["cypress"]
|
||||||
|
}
|
||||||
|
}
|
8086
package-lock.json
generated
8086
package-lock.json
generated
File diff suppressed because it is too large
Load diff
24
package.json
24
package.json
|
@ -56,13 +56,10 @@
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.6.4",
|
"@babel/core": "^7.6.4",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.3.0",
|
"@babel/preset-env": "^7.6.3",
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
|
"@babel/register": "^7.6.2",
|
||||||
"@babel/plugin-transform-spread": "^7.2.2",
|
|
||||||
"@babel/preset-env": "^7.3.1",
|
|
||||||
"@babel/register": "^7.0.0",
|
|
||||||
"autoprefixer": "^9.6.5",
|
"autoprefixer": "^9.6.5",
|
||||||
"babel-loader": "^8.0.5",
|
"babel-loader": "^8.0.6",
|
||||||
"bundlesize": "^0.18.0",
|
"bundlesize": "^0.18.0",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"csso": "^1.8.2",
|
"csso": "^1.8.2",
|
||||||
|
@ -86,19 +83,18 @@
|
||||||
"postcss-cli": "^6.1.3",
|
"postcss-cli": "^6.1.3",
|
||||||
"prettier": "^1.16.4",
|
"prettier": "^1.16.4",
|
||||||
"sinon": "^7.5.0",
|
"sinon": "^7.5.0",
|
||||||
"unminified-webpack-plugin": "^2.0.0",
|
"webpack": "^4.41.2",
|
||||||
"webpack": "^4.29.3",
|
"webpack-cli": "^3.3.9",
|
||||||
"webpack-cli": "^3.2.3",
|
"webpack-dev-middleware": "^3.7.2",
|
||||||
"webpack-dev-middleware": "^3.5.2",
|
"webpack-hot-middleware": "^2.25.0",
|
||||||
"webpack-hot-middleware": "^2.24.3",
|
|
||||||
"whatwg-fetch": "^1.0.0",
|
"whatwg-fetch": "^1.0.0",
|
||||||
"wrapper-webpack-plugin": "^2.1.0"
|
"wrapper-webpack-plugin": "^2.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"deepmerge": "^2.2.1",
|
"deepmerge": "^4.2.0",
|
||||||
"fuse.js": "3.4.2",
|
"fuse.js": "3.4.2",
|
||||||
"redux": "^3.3.1"
|
"redux": "^4.0.4"
|
||||||
},
|
},
|
||||||
"npmName": "choices.js",
|
"npmName": "choices.js",
|
||||||
"npmFileMap": [
|
"npmFileMap": [
|
||||||
|
@ -121,7 +117,7 @@
|
||||||
"bundlesize": [
|
"bundlesize": [
|
||||||
{
|
{
|
||||||
"path": "public/assets/scripts/choices.min.js",
|
"path": "public/assets/scripts/choices.min.js",
|
||||||
"maxSize": "25 kB"
|
"maxSize": "20 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "public/assets/styles/choices.min.css",
|
"path": "public/assets/styles/choices.min.css",
|
||||||
|
|
|
@ -1706,9 +1706,7 @@ class Choices {
|
||||||
const { choices } = this._store;
|
const { choices } = this._store;
|
||||||
const choiceLabel = label || value;
|
const choiceLabel = label || value;
|
||||||
const choiceId = choices ? choices.length + 1 : 1;
|
const choiceId = choices ? choices.length + 1 : 1;
|
||||||
const choiceElementId = `${this._baseId}-${
|
const choiceElementId = `${this._baseId}-${this._idNames.itemChoice}-${choiceId}`;
|
||||||
this._idNames.itemChoice
|
|
||||||
}-${choiceId}`;
|
|
||||||
|
|
||||||
this._store.dispatch(
|
this._store.dispatch(
|
||||||
addChoice({
|
addChoice({
|
||||||
|
@ -2086,5 +2084,5 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
Choices.userDefaults = {};
|
Choices.userDefaults = {};
|
||||||
// We cannot export default here due to Webpack: https://github.com/webpack/webpack/issues/3929
|
|
||||||
module.exports = Choices;
|
export default Choices;
|
||||||
|
|
|
@ -15,6 +15,11 @@ export default class WrappedElement {
|
||||||
return this.element.value;
|
return this.element.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set value(value) {
|
||||||
|
// you must define setter here otherwise it will be readonly property
|
||||||
|
this.element.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
conceal() {
|
conceal() {
|
||||||
// Hide passed input
|
// Hide passed input
|
||||||
this.element.classList.add(this.classNames.input);
|
this.element.classList.add(this.classNames.input);
|
||||||
|
|
|
@ -14,8 +14,7 @@ export default class WrappedInput extends WrappedElement {
|
||||||
this.element.value = joinedValues;
|
this.element.value = joinedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo figure out why we need this? Perhaps a babel issue
|
|
||||||
get value() {
|
get value() {
|
||||||
return super.value;
|
return this.element.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
webpack.config.base.js
Normal file
39
webpack.config.base.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const include = path.resolve(__dirname, './src/scripts');
|
||||||
|
const exclude = /node_modules/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import('webpack').Configuration}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
entry: ['./src/scripts/choices'],
|
||||||
|
output: {
|
||||||
|
library: 'Choices',
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
libraryExport: 'default',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
enforce: 'pre',
|
||||||
|
loader: 'eslint-loader',
|
||||||
|
test: /\.js?$/,
|
||||||
|
include,
|
||||||
|
exclude,
|
||||||
|
options: {
|
||||||
|
quiet: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'babel-loader',
|
||||||
|
test: /\.js?$/,
|
||||||
|
include,
|
||||||
|
exclude,
|
||||||
|
options: {
|
||||||
|
babelrc: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,42 +1,23 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { HotModuleReplacementPlugin } = require('webpack');
|
const { HotModuleReplacementPlugin } = require('webpack');
|
||||||
|
const deepMerge = require('deepmerge');
|
||||||
|
const baseConfig = require('./webpack.config.base');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = deepMerge(
|
||||||
mode: 'development',
|
baseConfig,
|
||||||
entry: [
|
{
|
||||||
'webpack/hot/dev-server',
|
mode: 'development',
|
||||||
'webpack-hot-middleware/client',
|
output: {
|
||||||
'./src/scripts/choices',
|
path: path.resolve(__dirname, './public'),
|
||||||
],
|
filename: 'choices.min.js',
|
||||||
output: {
|
publicPath: 'http://localhost:3001/assets/scripts/',
|
||||||
path: path.resolve('public'),
|
},
|
||||||
filename: 'choices.min.js',
|
entry: ['webpack/hot/dev-server', 'webpack-hot-middleware/client'],
|
||||||
publicPath: 'http://localhost:3001/assets/scripts/',
|
plugins: [new HotModuleReplacementPlugin()],
|
||||||
library: 'Choices',
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
},
|
},
|
||||||
plugins: [new HotModuleReplacementPlugin()],
|
{
|
||||||
module: {
|
arrayMerge(target, source) {
|
||||||
rules: [
|
return [...source, ...target];
|
||||||
{
|
},
|
||||||
enforce: 'pre',
|
|
||||||
test: /\.js?$/,
|
|
||||||
include: path.join(__dirname, 'src/scripts'),
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
query: {
|
|
||||||
configFile: '.eslintrc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js?$/,
|
|
||||||
include: path.join(__dirname, 'src/scripts'),
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
babelrc: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
);
|
||||||
|
|
|
@ -1,56 +1,47 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const deepMerge = require('deepmerge');
|
||||||
const WrapperPlugin = require('wrapper-webpack-plugin');
|
const WrapperPlugin = require('wrapper-webpack-plugin');
|
||||||
const UnminifiedWebpackPlugin = require('unminified-webpack-plugin');
|
|
||||||
|
|
||||||
const pkg = require('./package.json');
|
const baseConfig = require('./webpack.config.base');
|
||||||
|
const { name, version, author, homepage } = require('./package.json');
|
||||||
|
|
||||||
const banner = `/*! ${pkg.name} v${
|
const arrayMerge = (target, source) => [...source, ...target];
|
||||||
pkg.version
|
|
||||||
} | (c) ${new Date().getFullYear()} ${pkg.author} | ${pkg.homepage} */ \n`;
|
|
||||||
|
|
||||||
module.exports = {
|
const prodConfig = deepMerge(
|
||||||
mode: 'production',
|
baseConfig,
|
||||||
entry: ['./src/scripts/choices'],
|
{
|
||||||
output: {
|
mode: 'production',
|
||||||
path: path.join(__dirname, '/public/assets/scripts'),
|
output: {
|
||||||
filename: 'choices.min.js',
|
path: path.join(__dirname, '/public/assets/scripts'),
|
||||||
publicPath: '/public/assets/scripts/',
|
publicPath: '/public/assets/scripts/',
|
||||||
library: 'Choices',
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
auxiliaryComment: {
|
|
||||||
root: 'Window',
|
|
||||||
commonjs: 'CommonJS',
|
|
||||||
commonjs2: 'CommonJS2',
|
|
||||||
amd: 'AMD',
|
|
||||||
},
|
},
|
||||||
},
|
plugins: [
|
||||||
plugins: [
|
new WrapperPlugin({
|
||||||
new WrapperPlugin({
|
header: `/*! ${name} v${version} | © ${new Date().getFullYear()} ${author} | ${homepage} */ \n`,
|
||||||
header: banner,
|
}),
|
||||||
}),
|
|
||||||
new UnminifiedWebpackPlugin(),
|
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
enforce: 'pre',
|
|
||||||
test: /\.js?$/,
|
|
||||||
include: path.join(__dirname, 'src/scripts'),
|
|
||||||
exclude: /(node_modules|bower_components)/,
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
query: {
|
|
||||||
configFile: '.eslintrc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js?$/,
|
|
||||||
include: path.join(__dirname, 'src/scripts'),
|
|
||||||
exclude: /(node_modules|bower_components)/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
babelrc: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
arrayMerge,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
deepMerge(
|
||||||
|
prodConfig,
|
||||||
|
{
|
||||||
|
output: { filename: 'choices.js' },
|
||||||
|
optimization: { minimize: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arrayMerge,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
deepMerge(
|
||||||
|
prodConfig,
|
||||||
|
{ output: { filename: 'choices.min.js' } },
|
||||||
|
{
|
||||||
|
arrayMerge,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
Loading…
Reference in a new issue