1
0
Fork 0

chore(stack update): update the whole docsearch stack (#173)

* chore(stack update): update the whole docsearch stack

In an effort to reduce our stack diversity I am moving docsearch to:
- latest eslint
- prettier
- webpack 2
- babel 6 (babel 7 is soon to be released, we were on babel 5)
- babel-preset-env (support: IE >=9, Two latest version of evergreen
browsers).
- jest

* chore(contrib): remove develop branch, cc @redox
This commit is contained in:
Vincent Voyer 2017-03-17 16:22:00 +01:00 committed by GitHub
parent 25dbb4d7d3
commit 3c98ea5882
29 changed files with 3857 additions and 2274 deletions

View file

@ -1,8 +1,15 @@
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie >= 9"]
}
}],
"stage-3"
],
"env": {
"test": {
"plugins": ["babel-plugin-rewire"]
}
},
"stage": 2
},
}
}

View file

@ -1,3 +0,0 @@
{
"extends": "algolia"
}

3
.eslintrc.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
extends: ['algolia'],
};

View file

@ -5,13 +5,10 @@ before_install:
- git config --global user.name "algobot"
- rvm install 2.2.0
- rvm use 2.2.0
before_cache: npm prune
script: "./scripts/test-ci"
after_script: "./scripts/travis-after-script"
branches:
only:
- master
- develop
sudo: false
cache:
yarn: true

View file

@ -1,7 +1,7 @@
Hi (future) collaborator!
**tl;dr;**
- submit pull requests to develop branch
- submit pull requests to master branch
- use [conventional changelog](https://github.com/ajoslin/conventional-changelog/blob/master/conventions/angular.md) commit style messages
- squash your commits
- have fun
@ -26,9 +26,6 @@ Hi (future) collaborator!
- [Releasing](#releasing)
- [Releasing v1](#releasing-v1)
- [Beta releases](#beta-releases)
- [Hotfixes](#hotfixes)
- [Releasing hotfixes](#releasing-hotfixes)
- [Documentation updates](#documentation-updates)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@ -36,10 +33,6 @@ Hi (future) collaborator!
Have a fix or a new feature? [Search for corresponding issues](https://github.com/algolia/docsearch/issues) first then create a new one.
Always check the status of the [develop branch](https://github.com/algolia/docsearch/tree/develop) for the freshest code.
Always submit pull requests to the develop branch.
# Development workflow
## Local example
@ -141,7 +134,7 @@ Example:
# When are issues closed?
Once the a fix is done, having the fix in the `develop` branch is not sufficient, it needs to be part of a release for us to close the issue.
Once the a fix is done, having the fix in the `master` branch is not sufficient, it needs to be part of a release for us to close the issue.
So that you never ask yourself "Is this released?".
@ -159,8 +152,6 @@ You must be on the master branch.
npm run release
```
This task will merge develop into master.
## Releasing v1
```sh
@ -169,40 +160,21 @@ git pull
npm run release
```
We use the `v1` branch as a way to push fixes to the first version of DocSearch. Never merge `master` or `develop` into `v1` and
We use the `v1` branch as a way to push fixes to the first version of DocSearch. Do not merge `master` into `v1` and
vice versa.
## Beta releases
You must be on the develop branch.
You must be on the master branch.
```sh
npm run release:beta
```
This task will release a beta version of what is currently in develop branch.
This task will release a beta version of what is currently in master branch.
It will not update the `latest` tag of the npm release nor update jsDelivr /2/.
# Hotfixes
All our work is done on the develop branch but it could be necessary to push a hotfix to the master
branch and do a patch release. To fix a very important bug.
For this, you should:
- add `hotfix` to the commit message **body**
- submit your pull request to the master branch
## Releasing hotfixes
You must be on the master branch.
This task will not merge develop in master, only release current master.
```sh
HOTFIX=1 npm run release
```
## Documentation updates
If you have important documentation update to release without wanting to release

View file

@ -4,7 +4,7 @@ docsearch({
apiKey: 'e3d767b736584dbe6d4c35f7cf7d4633',
indexName: 'react-native',
inputSelector: '#search-input',
debug: true
debug: true,
});
document.getElementById('search-input').focus();

View file

@ -1 +1,2 @@
/* eslint-disable import/no-commonjs */
module.exports = require('./src/lib/main.js');

View file

@ -15,54 +15,65 @@
"release": "./scripts/release",
"release:beta": "./scripts/release-beta",
"lint": "eslint .",
"test": "BABEL_ENV=test mocha --timeout 6000 --reporter dot ./test/helpers.js ./test/*-test.js",
"test:watch": "BABEL_ENV=test mocha --reporter min --watch ./test/helpers.js ./test/*-test.js",
"test:coverage": "./scripts/test-coverage",
"gh-pages": "./scripts/gh-pages"
"test": "jest --coverage",
"test:watch": "jest --watch",
"gh-pages": "./scripts/gh-pages",
"precommit": "lint-staged"
},
"lint-staged": {
"*.js": [
"prettier --write --single-quote --trailing-comma es5",
"git add"
]
},
"files": [
"dist/"
],
"author": "Algolia <support@algolia.com> (https://github.com/algolia/)",
"license": "MIT",
"repository": "algolia/docsearch",
"devDependencies": {
"autoprefixer": "^6.3.6",
"babel": "^5.8.29",
"babel-core": "^5.8.29",
"babel-eslint": "^4.1.3",
"babel-istanbul": "^0.5.9",
"babel-loader": "^5.3.2",
"babel-plugin-rewire": "^0.1.22",
"conventional-changelog": "^0.5.1",
"coveralls": "^2.11.9",
"autoprefixer": "^6.7.7",
"babel-cli": "^6.24.0",
"babel-core": "^6.24.0",
"babel-eslint": "^7.1.1",
"babel-istanbul": "^0.12.2",
"babel-loader": "^6.4.1",
"babel-plugin-rewire": "^1.0.0",
"babel-preset-env": "^1.2.2",
"babel-preset-stage-3": "^6.22.0",
"conventional-changelog-cli": "^1.3.1",
"cssnano": "^3.7.0",
"doctoc": "^0.15.0",
"eslint": "^1.6.0",
"eslint-config-airbnb": "^0.1.0",
"eslint-config-algolia": "^4.7.0",
"doctoc": "^1.3.0",
"eslint": "^3.17.1",
"eslint-config-algolia": "^6.0.1",
"eslint-config-prettier": "^1.5.0",
"eslint-import-resolver-webpack": "^0.8.1",
"eslint-plugin-algolia": "^1.5.0",
"eslint-plugin-react": "^3.5.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jest": "^19.0.1",
"expect": "^1.20.1",
"gh-pages": "^0.12.0",
"jsdom": "^7.1.1",
"json": "^9.0.4",
"mocha": "^2.5.3",
"mocha-jsdom": "^1.1.0",
"mocha-lcov-reporter": "^1.2.0",
"jest": "^19.0.2",
"jsdom": "^9.12.0",
"json": "^9.0.6",
"mversion": "^1.10.1",
"nd": "^1.2.0",
"node-sass": "^3.7.0",
"onchange": "^2.5.0",
"postcss-cli": "^2.5.2",
"pretty-bytes": "^2.0.1",
"node-sass": "^4.5.0",
"onchange": "^3.2.1",
"postcss-cli": "^3.0.0",
"prettier": "^0.22.0",
"pretty-bytes-cli": "^2.0.0",
"semver": "^5.1.0",
"sinon": "^1.17.4",
"uglify-js": "^2.6.2",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1"
"sinon": "^2.0.0",
"uglify-js": "^2.8.13",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.2"
},
"peerDependencies": {},
"dependencies": {
"algoliasearch": "^3.18.0",
"autocomplete.js": "^0.25.0",
"algoliasearch": "^3.22.1",
"autocomplete.js": "^0.27.0",
"hogan.js": "^3.0.2",
"to-factory": "^1.0.0"
}

View file

@ -7,18 +7,17 @@ LICENSE="/*! ${NAME} ${VERSION:-UNRELEASED} | © Algolia | github.com/algolia/do
DIST_DIR="dist/cdn"
DIST_FILE="$DIST_DIR/${NAME}.css"
DIST_FILE_MIN="$DIST_DIR/${NAME}.min.css"
DIST_FILE_MAP="$DIST_DIR/${NAME}.min.css.map"
mkdir -p "$DIST_DIR"
# ./dist/cdn/docsearch.css
echo "$LICENSE" > "$DIST_FILE";
node-sass --output-style expanded ./src/styles/main.scss \
| postcss --use autoprefixer \
>> "$DIST_FILE"
| postcss --use autoprefixer -o "$DIST_FILE"
# ./dist/cdn/docsearch.min.css
postcss --use cssnano "$DIST_FILE" \
>> "$DIST_FILE_MIN"
postcss "$DIST_FILE" --use cssnano --map "$DIST_FILE_MAP" -o "$DIST_FILE_MIN"
gzip_size=$(gzip -9 < $DIST_FILE_MIN | wc -c | pretty-bytes)
echo "=> $DIST_FILE_MIN gzipped will weight $gzip_size-bytes"

View file

@ -8,24 +8,30 @@ import semver from 'semver';
import currentVersion from '../src/lib/version.js';
if (!process.env.VERSION) {
throw new Error('bump: Usage is VERSION=MAJOR.MINOR.PATCH scripts/bump-package-version.js');
throw new Error(
'bump: Usage is VERSION=MAJOR.MINOR.PATCH scripts/bump-package-version.js'
);
}
let newVersion = process.env.VERSION;
const newVersion = process.env.VERSION;
if (!semver.valid(newVersion)) {
throw new Error('bump: Provided new version (' + newVersion + ') is not a valid version per semver');
throw new Error(
`bump: Provided new version (${newVersion}) is not a valid version per semver`
);
}
if (semver.gte(currentVersion, newVersion)) {
throw new Error('bump: Provided new version is not higher than current version (' + newVersion + ' <= ' + currentVersion + ')');
throw new Error(
`bump: Provided new version is not higher than current version (${newVersion} <= ${currentVersion})`
);
}
console.log('Bumping ' + newVersion);
console.log(`Bumping ${newVersion}`);
console.log('..Updating src/lib/version.js');
let versionFile = path.join(__dirname, '../src/lib/version.js');
let newContent = "export default '" + newVersion + "';\n";
const versionFile = path.join(__dirname, '../src/lib/version.js');
const newContent = `export default '${newVersion}';\n`;
fs.writeFileSync(versionFile, newContent);
console.log('..Updating package.json, npm-shrinwrap.json');

View file

@ -2,13 +2,6 @@
npm run build:css
# /bundle.js in memory
webpack-dev-server \
--config webpack.dev.config.babel.js \
--hot \
--inline \
--no-info & \
# rebuild docsearch.css and docsearch.min.css
onchange './src/styles/*.scss' -- npm run build:css & \
webpack-dev-server --config webpack.dev.config.babel.js &
onchange './src/styles/*.scss' -- npm run build:css &
wait

View file

@ -24,12 +24,6 @@ printf "\n\nRelease: update working tree"
git pull origin master
git fetch origin --tags
if [ $HOTFIX == '0' ]; then
printf "\n\nRelease: merge develop branch"
git fetch origin develop
git merge origin/develop
fi
printf "Release: yarn"
yarn
@ -79,13 +73,6 @@ printf "\n\nRelease: push to github, publish on npm"
git push origin master
git push origin --tags
npm publish
# also update beta
npm dist-tag add docsearch.js@$newVersion beta
git checkout develop
git pull origin develop
git merge master
git push origin develop
git checkout master
printf "Release:
Package was published to npm.

View file

@ -1,88 +0,0 @@
#!/usr/bin/env bash
set -e # exit when error
if [[ -n $(npm owner add `npm whoami`) ]]; then
printf "Beta release: Not an owner of the npm repo, ask for it"
exit 1
fi
currentBranch=`git rev-parse --abbrev-ref HEAD`
if [ $currentBranch != 'develop' ]; then
printf "Beta release: You must be on develop"
exit 1
fi
if [[ -n $(git status --porcelain) ]]; then
printf "Beta release: Working tree is not clean (git status)"
exit 1
fi
printf "\n\nBeta release: update working tree"
git pull origin develop
git fetch origin --tags
printf "Beta release: yarn"
yarn
currentVersion=`cat package.json | json version`
# if not on a beta version already
if [[ $currentVersion != *"-beta"* || $CHOOSE_BUMP ]]
then
# header
printf "\n\nBeta release: current version is $currentVersion"
printf "\nBeta release: a changelog will be generated only if a fix/feat/performance/breaking token is found in git log"
printf "\nBeta release: you must choose a new ve.rs.ion (semver)"
printf "\nBeta release: press q to exit the next screen\n\n"
# preview changelog
read -p "=> Beta release: press [ENTER] to view changes since latest version.."
# nd (markdown renderer in terminal)
# has some output going on to stderr because of node v4, no big deal
conventional-changelog -p angular | nd | less -r 2>/dev/null
# choose and bump new version
# printf "\n\nBeta release: Please enter the new chosen version > "
printf "\n=> Beta release: please type the new chosen version (-beta will be automatically appended) > "
read -e newVersion
newVersion="$newVersion-beta.0"
else
# when already on a beta version, let's bump the beta-.X
newVersion=`semver ${currentVersion} -i prerelease -preid beta`
read -p "
=> Beta release: The new version will be ${newVersion},
press [ENTER] to continue, CTRL+C to abort.
You can force specifying a different bump by using CHOOSE_BUMP=1 npm run release-beta"
fi
VERSION=$newVersion babel-node ./scripts/bump-package-version.js
# build new version
NODE_ENV=production VERSION=$newVersion npm run build
# regenerate readme TOC
printf "\n\nBeta release: generate TOCS"
npm run doctoc
# add a timestamp fake file to dist/ to avoid having beta released published to jsdelivr automatically
# https://github.com/jsdelivr/jsdelivr/pull/8107#issuecomment-159562676
# You will have to close the open PR afterwards
timestamp=$(date "+%Y.%m.%d-%H.%M.%S")
tmpfile="dist/avoid-jsdelivr-beta-publish-$timestamp"
touch $tmpfile
# git add and tag
commitMessage="v$newVersion\n\n$changelog"
git add src/lib/version.js package.json CHANGELOG.md CONTRIBUTING.md README.md
printf "$commitMessage" | git commit --file -
printf "\n\nBeta release: almost done, check everything in another terminal tab.\n"
read -p "=> Beta release: when ready, press [ENTER] to push to github and publish the package to the beta channel"
printf "\n\nBeta release: push to github, publish on npm"
git push origin develop
npm publish --tag beta
rm $tmpfile

View file

@ -2,8 +2,7 @@
set -ev # exit when error
./scripts/validate-pr-done-on-develop
npm run test:coverage
npm run test
npm prune
NODE_ENV=production npm run build
./scripts/validate-commit-msgs

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Will push coverage info to coveralls. Should be ran from Travis, in the
# `after_script` section
$(npm bin)/coveralls < ./coverage/lcov.info

View file

@ -25,7 +25,7 @@ fi
if [ "$RANGE" == "" ]; then
# locally
RANGE="origin/develop..HEAD"
RANGE="origin/master..HEAD"
elif [[ "$RANGE" == *...* ]]; then
# Travis sends the ranges with 3 dots. Git only wants 2.
RANGE=`echo $TRAVIS_COMMIT_RANGE | sed 's/\.\.\./../'`

View file

@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -e # exit when error
COMMIT_MSG=`git log --format=%B --no-merges -n 1`
if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
MSG="No need to check pull request done on develop branch when not in a pull request"
EXIT=0
elif [[ "$COMMIT_MSG" =~ "hotfix" ]] && [ "$TRAVIS_BRANCH" == 'master' ]; then
MSG="Hotfix submitted to master, good"
EXIT=0
elif [ "$TRAVIS_BRANCH" != 'develop' ]; then
MSG="Pull request must be done on develop branch"
EXIT=1
fi
echo $MSG;
exit $EXIT;

View file

@ -29,65 +29,81 @@ const usage = `Usage:
[ autocompleteOptions.{hint,debug} ]
})`;
class DocSearch {
constructor({
apiKey,
indexName,
inputSelector,
appId = 'BH4D9OD16A',
debug = false,
algoliaOptions = {},
autocompleteOptions = {
debug: false,
hint: false,
autoselect: true
},
transformData = false,
handleSelected = false,
enhancedSearchInput = false,
layout = 'collumns'
}) {
DocSearch.checkArguments({apiKey, indexName, inputSelector, debug, algoliaOptions,
autocompleteOptions, transformData, handleSelected, enhancedSearchInput, layout});
constructor(
{
apiKey,
indexName,
inputSelector,
appId = 'BH4D9OD16A',
debug = false,
algoliaOptions = {},
autocompleteOptions = {
debug: false,
hint: false,
autoselect: true,
},
transformData = false,
handleSelected = false,
enhancedSearchInput = false,
layout = 'collumns',
}
) {
DocSearch.checkArguments({
apiKey,
indexName,
inputSelector,
debug,
algoliaOptions,
autocompleteOptions,
transformData,
handleSelected,
enhancedSearchInput,
layout,
});
this.apiKey = apiKey;
this.appId = appId;
this.indexName = indexName;
this.input = DocSearch.getInputFromSelector(inputSelector);
this.algoliaOptions = {hitsPerPage: 5, ...algoliaOptions};
const autocompleteOptionsDebug = autocompleteOptions && autocompleteOptions.debug ?
autocompleteOptions.debug : false;
this.algoliaOptions = { hitsPerPage: 5, ...algoliaOptions };
const autocompleteOptionsDebug = autocompleteOptions &&
autocompleteOptions.debug
? autocompleteOptions.debug
: false;
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
this.autocompleteOptions = autocompleteOptions;
this.autocompleteOptions.cssClasses = {
prefix: 'ds'
prefix: 'ds',
};
handleSelected = handleSelected || this.handleSelected;
this.isSimpleLayout = (layout === 'simple');
this.isSimpleLayout = layout === 'simple';
this.client = algoliasearch(this.appId, this.apiKey);
this.client.addAlgoliaAgent('docsearch.js ' + version);
this.client.addAlgoliaAgent(`docsearch.js ${version}`);
if (enhancedSearchInput) {
this.input = DocSearch.injectSearchBox(this.input);
}
this.autocomplete = autocomplete(this.input, autocompleteOptions, [{
source: this.getAutocompleteSource(transformData),
templates: {
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
footer: templates.footer,
empty: DocSearch.getEmptyTemplate()
}
}]);
this.autocomplete = autocomplete(this.input, autocompleteOptions, [
{
source: this.getAutocompleteSource(transformData),
templates: {
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
footer: templates.footer,
empty: DocSearch.getEmptyTemplate(),
},
},
]);
this.autocomplete.on(
'autocomplete:selected',
handleSelected.bind(null, this.autocomplete.autocomplete)
);
this.autocomplete.on(
'autocomplete:shown',
this.handleShown.bind(null, this.input)
this.handleShown.bind(null, this.input)
);
if (enhancedSearchInput) {
@ -107,16 +123,17 @@ class DocSearch {
}
if (!DocSearch.getInputFromSelector(args.inputSelector)) {
throw new Error(`Error: No input element in the page matches ${args.inputSelector}`);
throw new Error(
`Error: No input element in the page matches ${args.inputSelector}`
);
}
}
static injectSearchBox(input) {
input.before(templates.searchBox);
var new_input = input.prev().prev().find('input');
const newInput = input.prev().prev().find('input');
input.remove();
return new_input;
return newInput;
}
static bindSearchBoxEvent() {
@ -126,9 +143,9 @@ class DocSearch {
autocomplete.autocomplete.setVal('');
});
$('input#docsearch').on('keyup', function() {
var searchbox = document.querySelector('input#docsearch');
var reset = document.querySelector('.searchbox [type="reset"]');
$('input#docsearch').on('keyup', () => {
const searchbox = document.querySelector('input#docsearch');
const reset = document.querySelector('.searchbox [type="reset"]');
reset.className = 'searchbox__reset';
if (searchbox.value.length === 0) {
reset.className += ' hide';
@ -144,7 +161,7 @@ class DocSearch {
* @returns {void}
*/
static getInputFromSelector(selector) {
let input = $(selector).filter('input');
const input = $(selector).filter('input');
return input.length ? $(input[0]) : null;
}
@ -158,86 +175,104 @@ class DocSearch {
*/
getAutocompleteSource(transformData) {
return (query, callback) => {
this.client.search([{
indexName: this.indexName,
query: query,
params: this.algoliaOptions
}]).then((data) => {
let hits = data.results[0].hits;
if (transformData) {
hits = transformData(hits) || hits;
}
callback(DocSearch.formatHits(hits));
});
this.client
.search([
{
indexName: this.indexName,
query,
params: this.algoliaOptions,
},
])
.then(data => {
let hits = data.results[0].hits;
if (transformData) {
hits = transformData(hits) || hits;
}
callback(DocSearch.formatHits(hits));
});
};
}
// Given a list of hits returned by the API, will reformat them to be used in
// a Hogan template
static formatHits(receivedHits) {
let clonedHits = utils.deepClone(receivedHits);
let hits = clonedHits.map((hit) => {
const clonedHits = utils.deepClone(receivedHits);
const hits = clonedHits.map(hit => {
if (hit._highlightResult) {
hit._highlightResult = utils.mergeKeyWithParent(hit._highlightResult, 'hierarchy');
hit._highlightResult = utils.mergeKeyWithParent(
hit._highlightResult,
'hierarchy'
);
}
return utils.mergeKeyWithParent(hit, 'hierarchy');
});
// Group hits by category / subcategory
var groupedHits = utils.groupBy(hits, 'lvl0');
let groupedHits = utils.groupBy(hits, 'lvl0');
$.each(groupedHits, (level, collection) => {
const groupedHitsByLvl1 = utils.groupBy(collection, 'lvl1');
const flattenedHits = utils.flattenAndFlagFirst(groupedHitsByLvl1, 'isSubCategoryHeader');
const flattenedHits = utils.flattenAndFlagFirst(
groupedHitsByLvl1,
'isSubCategoryHeader'
);
groupedHits[level] = flattenedHits;
});
groupedHits = utils.flattenAndFlagFirst(groupedHits, 'isCategoryHeader');
// Translate hits into smaller objects to be send to the template
return groupedHits.map((hit) => {
return groupedHits.map(hit => {
const url = DocSearch.formatURL(hit);
const category = utils.getHighlightedValue(hit, 'lvl0');
const subcategory = utils.getHighlightedValue(hit, 'lvl1') || category;
const displayTitle = utils.compact([
utils.getHighlightedValue(hit, 'lvl2') || subcategory,
utils.getHighlightedValue(hit, 'lvl3'),
utils.getHighlightedValue(hit, 'lvl4'),
utils.getHighlightedValue(hit, 'lvl5'),
utils.getHighlightedValue(hit, 'lvl6')
]).join('<span class="aa-suggestion-title-separator" aria-hidden="true"> </span>');
const displayTitle = utils
.compact([
utils.getHighlightedValue(hit, 'lvl2') || subcategory,
utils.getHighlightedValue(hit, 'lvl3'),
utils.getHighlightedValue(hit, 'lvl4'),
utils.getHighlightedValue(hit, 'lvl5'),
utils.getHighlightedValue(hit, 'lvl6'),
])
.join(
'<span class="aa-suggestion-title-separator" aria-hidden="true"> </span>'
);
const text = utils.getSnippetedValue(hit, 'content');
const isTextOrSubcatoryNonEmpty = (subcategory && subcategory !== '') ||
(displayTitle && displayTitle !== '');
const isLvl1EmptyOrDuplicate = !subcategory || subcategory === '' || subcategory === category;
const isLvl2 = displayTitle && displayTitle !== '' && displayTitle !== subcategory;
const isLvl1 = !isLvl2 && (subcategory && subcategory !== '' && subcategory !== category);
const isLvl1EmptyOrDuplicate = !subcategory ||
subcategory === '' ||
subcategory === category;
const isLvl2 = displayTitle &&
displayTitle !== '' &&
displayTitle !== subcategory;
const isLvl1 = !isLvl2 &&
(subcategory && subcategory !== '' && subcategory !== category);
const isLvl0 = !isLvl1 && !isLvl2;
return {
isLvl0: isLvl0,
isLvl1: isLvl1,
isLvl2: isLvl2,
isLvl1EmptyOrDuplicate: isLvl1EmptyOrDuplicate,
isLvl0,
isLvl1,
isLvl2,
isLvl1EmptyOrDuplicate,
isCategoryHeader: hit.isCategoryHeader,
isSubCategoryHeader: hit.isSubCategoryHeader,
isTextOrSubcatoryNonEmpty: isTextOrSubcatoryNonEmpty,
category: category,
subcategory: subcategory,
isTextOrSubcatoryNonEmpty,
category,
subcategory,
title: displayTitle,
text: text,
url: url
text,
url,
};
});
}
static formatURL(hit) {
const {url, anchor} = hit;
const { url, anchor } = hit;
if (url) {
const containsAnchor = url.indexOf('#') !== -1;
if (containsAnchor) return url;
else if (anchor) return `${hit.url}#${hit.anchor}`;
return url;
}
else if (anchor) return `#${hit.anchor}`;
} else if (anchor) return `#${hit.anchor}`;
/* eslint-disable */
console.warn('no anchor nor url for : ', JSON.stringify(hit));
/* eslint-enable */
@ -245,17 +280,15 @@ class DocSearch {
}
static getEmptyTemplate() {
return (args) => {
return Hogan.compile(templates.empty).render(args);
};
return args => Hogan.compile(templates.empty).render(args);
}
static getSuggestionTemplate(isSimpleLayout) {
const stringTemplate = isSimpleLayout ? templates.suggestionSimple : templates.suggestion;
const stringTemplate = isSimpleLayout
? templates.suggestionSimple
: templates.suggestion;
const template = Hogan.compile(stringTemplate);
return (suggestion) => {
return template.render(suggestion);
};
return suggestion => template.render(suggestion);
}
handleSelected(input, event, suggestion) {
@ -271,10 +304,12 @@ class DocSearch {
middleOfWindow = 900;
}
const alignClass = middleOfInput - middleOfWindow >= 0 ?
'algolia-autocomplete-right' : 'algolia-autocomplete-left';
const otherAlignClass = middleOfInput - middleOfWindow < 0 ?
'algolia-autocomplete-right' : 'algolia-autocomplete-left';
const alignClass = middleOfInput - middleOfWindow >= 0
? 'algolia-autocomplete-right'
: 'algolia-autocomplete-left';
const otherAlignClass = middleOfInput - middleOfWindow < 0
? 'algolia-autocomplete-right'
: 'algolia-autocomplete-left';
const autocompleteWrapper = $('.algolia-autocomplete');
if (!autocompleteWrapper.hasClass(alignClass)) {
@ -288,5 +323,3 @@ class DocSearch {
}
export default DocSearch;

View file

@ -1,31 +1,19 @@
/* eslint-env mocha */
import jsdom from 'mocha-jsdom';
import expect from 'expect';
import utils from '../utils.js';
describe('utils', () => {
var utils;
jsdom();
before(() => {
// We need to load utils from here as it depends on Zepto, which itself
// needs jsdom to be called before being loaded.
utils = require('../src/lib/utils.js');
});
describe('mergeKeyWithParent', () => {
it('should move all subkeys to parent', () => {
// Given
let input = {
const input = {
name: 'foo',
hierarchy: {
lvl0: 'bar',
lvl1: 'baz'
}
lvl1: 'baz',
},
};
// When
let actual = utils.mergeKeyWithParent(input, 'hierarchy');
const actual = utils.mergeKeyWithParent(input, 'hierarchy');
// Then
expect(actual.lvl0).toEqual('bar');
@ -33,59 +21,60 @@ describe('utils', () => {
});
it('should delete the attribute', () => {
// Given
let input = {
const input = {
name: 'foo',
hierarchy: {
lvl0: 'bar',
lvl1: 'baz'
}
lvl1: 'baz',
},
};
// When
let actual = utils.mergeKeyWithParent(input, 'hierarchy');
const actual = utils.mergeKeyWithParent(input, 'hierarchy');
// Then
expect(actual.hierarchy).toEqual(undefined);
});
it('should overwrite key if present', () => {
// Given
let input = {
const input = {
name: 'foo',
lvl0: 42,
hierarchy: {
lvl0: 'bar',
lvl1: 'baz'
}
lvl1: 'baz',
},
};
// When
let actual = utils.mergeKeyWithParent(input, 'hierarchy');
const actual = utils.mergeKeyWithParent(input, 'hierarchy');
// Then
expect(actual.lvl0).toNotEqual(42);
expect(actual.lvl0).not.toEqual(42);
expect(actual.lvl0).toEqual('bar');
});
it('should do nothing if no such key', () => {
// Given
let input = {
name: 'foo'
const input = {
name: 'foo',
};
// When
let actual = utils.mergeKeyWithParent(input, 'hierarchy');
const actual = utils.mergeKeyWithParent(input, 'hierarchy');
// Then
expect(actual).toBe(input);
});
it('should throw an error if key is no an object', () => {
// Given
let input = {
const input = {
name: 'foo',
hierarchy: 42
hierarchy: 42,
};
// When
let actual = utils.mergeKeyWithParent(input, 'hierarchy');
const actual = utils.mergeKeyWithParent(input, 'hierarchy');
// Then
expect(actual).toBe(input);
@ -95,59 +84,59 @@ describe('utils', () => {
describe('groupBy', () => {
it('group by specified key', () => {
// Given
let input = [
{name: 'Tim', category: 'devs'},
{name: 'Vincent', category: 'devs'},
{name: 'Ben', category: 'sales'},
{name: 'Jeremy', category: 'sales'},
{name: 'AlexS', category: 'devs'},
{name: 'AlexK', category: 'sales'}
const input = [
{ name: 'Tim', category: 'devs' },
{ name: 'Vincent', category: 'devs' },
{ name: 'Ben', category: 'sales' },
{ name: 'Jeremy', category: 'sales' },
{ name: 'AlexS', category: 'devs' },
{ name: 'AlexK', category: 'sales' },
];
// When
let actual = utils.groupBy(input, 'category');
const actual = utils.groupBy(input, 'category');
// Expect
expect(actual).toEqual({
devs: [
{name: 'Tim', category: 'devs'},
{name: 'Vincent', category: 'devs'},
{name: 'AlexS', category: 'devs'}
{ name: 'Tim', category: 'devs' },
{ name: 'Vincent', category: 'devs' },
{ name: 'AlexS', category: 'devs' },
],
sales: [
{name: 'Ben', category: 'sales'},
{name: 'Jeremy', category: 'sales'},
{name: 'AlexK', category: 'sales'}
]
{ name: 'Ben', category: 'sales' },
{ name: 'Jeremy', category: 'sales' },
{ name: 'AlexK', category: 'sales' },
],
});
});
it('group by key considering lowercase forms', () => {
// Given
let input = [
{name: 'Tim', category: 'devs'},
{name: 'Vincent', category: 'DeVs'}
const input = [
{ name: 'Tim', category: 'devs' },
{ name: 'Vincent', category: 'DeVs' },
];
// When
let actual = utils.groupBy(input, 'category');
const actual = utils.groupBy(input, 'category');
// Expect
expect(actual).toEqual({
devs: [
{name: 'Tim', category: 'devs'},
{name: 'Vincent', category: 'DeVs'}
]
{ name: 'Tim', category: 'devs' },
{ name: 'Vincent', category: 'DeVs' },
],
});
});
it('throw an error if key does not exist', () => {
// Given
let input = [
{name: 'Tim'},
{name: 'Vincent'},
{name: 'Ben'},
{name: 'Jeremy'},
{name: 'AlexS'},
{name: 'AlexK'}
const input = [
{ name: 'Tim' },
{ name: 'Vincent' },
{ name: 'Ben' },
{ name: 'Jeremy' },
{ name: 'AlexS' },
{ name: 'AlexK' },
];
// When
@ -160,20 +149,17 @@ describe('utils', () => {
describe('values', () => {
it('should extract all values', () => {
// Given
let input = {
const input = {
foo: 42,
bar: true,
baz: 'yep'
baz: 'yep',
};
// Given
let actual = utils.values(input);
const actual = utils.values(input);
// Then
expect(actual.length).toEqual(3);
expect(actual).toInclude(42);
expect(actual).toInclude(true);
expect(actual).toInclude('yep');
expect(actual).toEqual([42, true, 'yep']);
});
});
@ -181,10 +167,10 @@ describe('utils', () => {
// flatten values
it('should flatten array on level deep', () => {
// Given
let input = [1, 2, [3, 4], [5, 6]];
const input = [1, 2, [3, 4], [5, 6]];
// Given
let actual = utils.flatten(input);
const actual = utils.flatten(input);
// Then
expect(actual).toEqual([1, 2, 3, 4, 5, 6]);
@ -194,30 +180,30 @@ describe('utils', () => {
describe('flattenAndFlagFirst', () => {
it('should flatten all values', () => {
// Given
let input = {
const input = {
devs: [
{name: 'Tim', category: 'dev'},
{name: 'Vincent', category: 'dev'},
{name: 'AlexS', category: 'dev'}
{ name: 'Tim', category: 'dev' },
{ name: 'Vincent', category: 'dev' },
{ name: 'AlexS', category: 'dev' },
],
sales: [
{name: 'Ben', category: 'sales'},
{name: 'Jeremy', category: 'sales'},
{name: 'AlexK', category: 'sales'}
]
{ name: 'Ben', category: 'sales' },
{ name: 'Jeremy', category: 'sales' },
{ name: 'AlexK', category: 'sales' },
],
};
// When
let actual = utils.flattenAndFlagFirst(input, 'isTop');
const actual = utils.flattenAndFlagFirst(input, 'isTop');
// Then
expect(actual).toEqual([
{name: 'Tim', category: 'dev', isTop: true},
{name: 'Vincent', category: 'dev', isTop: false},
{name: 'AlexS', category: 'dev', isTop: false},
{name: 'Ben', category: 'sales', isTop: true},
{name: 'Jeremy', category: 'sales', isTop: false},
{name: 'AlexK', category: 'sales', isTop: false}
{ name: 'Tim', category: 'dev', isTop: true },
{ name: 'Vincent', category: 'dev', isTop: false },
{ name: 'AlexS', category: 'dev', isTop: false },
{ name: 'Ben', category: 'sales', isTop: true },
{ name: 'Jeremy', category: 'sales', isTop: false },
{ name: 'AlexK', category: 'sales', isTop: false },
]);
});
});
@ -225,10 +211,10 @@ describe('utils', () => {
describe('compact', () => {
it('should clear all falsy elements from the array', () => {
// Given
let input = [42, false, null, undefined, '', [], 'foo'];
const input = [42, false, null, undefined, '', [], 'foo'];
// When
let actual = utils.compact(input);
const actual = utils.compact(input);
// Then
expect(actual).toEqual([42, [], 'foo']);
@ -238,44 +224,44 @@ describe('utils', () => {
describe('getHighlightedValue', () => {
it('should return the highlighted version if exists', () => {
// Given
let input = {
const input = {
_highlightResult: {
text: {
value: '<mark>foo</mark>'
}
value: '<mark>foo</mark>',
},
},
text: 'foo'
text: 'foo',
};
// When
let actual = utils.getHighlightedValue(input, 'text');
const actual = utils.getHighlightedValue(input, 'text');
// Then
expect(actual).toEqual('<mark>foo</mark>');
});
it('should return the default key if no highlighted value', () => {
// Given
let input = {
const input = {
_highlightResult: {
text: { }
text: {},
},
text: 'foo'
text: 'foo',
};
// When
let actual = utils.getHighlightedValue(input, 'text');
const actual = utils.getHighlightedValue(input, 'text');
// Then
expect(actual).toEqual('foo');
});
it('should return the default key if no highlight results', () => {
// Given
let input = {
text: 'foo'
const input = {
text: 'foo',
};
// When
let actual = utils.getHighlightedValue(input, 'text');
const actual = utils.getHighlightedValue(input, 'text');
// Then
expect(actual).toEqual('foo');
@ -285,64 +271,64 @@ describe('utils', () => {
describe('getSnippetedValue', () => {
it('should return the key value if no snippet returned', () => {
// Given
let input = {
text: 'Foo'
const input = {
text: 'Foo',
};
// When
let actual = utils.getSnippetedValue(input, 'text');
const actual = utils.getSnippetedValue(input, 'text');
// Then
expect(actual).toEqual('Foo');
});
it('should return the key value if no snippet for this key', () => {
// Given
let input = {
const input = {
_snippetResult: {
content: {
value: '<mark>Bar</mark>'
}
value: '<mark>Bar</mark>',
},
},
text: 'Foo',
content: 'Bar'
content: 'Bar',
};
// When
let actual = utils.getSnippetedValue(input, 'text');
const actual = utils.getSnippetedValue(input, 'text');
// Then
expect(actual).toEqual('Foo');
});
it('should add ellipsis at the start if snippet does not start with a capital letter', () => {
// Given
let input = {
const input = {
_snippetResult: {
text: {
value: 'this is the <mark>end</mark> of a sentence.'
}
value: 'this is the <mark>end</mark> of a sentence.',
},
},
text: 'this is the end of a sentence.'
text: 'this is the end of a sentence.',
};
// When
let actual = utils.getSnippetedValue(input, 'text');
const actual = utils.getSnippetedValue(input, 'text');
// Then
expect(actual).toEqual('…this is the <mark>end</mark> of a sentence.');
});
it('should add ellipsis at the end if snippet does not end with a terminal point', () => {
// Given
let input = {
const input = {
_snippetResult: {
text: {
value: 'This is an <mark>finished</mark> sentence'
}
value: 'This is an <mark>finished</mark> sentence',
},
},
text: 'This is an <mark>finished</mark> sentence'
text: 'This is an <mark>finished</mark> sentence',
};
// When
let actual = utils.getSnippetedValue(input, 'text');
const actual = utils.getSnippetedValue(input, 'text');
// Then
expect(actual).toEqual('This is an <mark>finished</mark> sentence…');
@ -352,33 +338,33 @@ describe('utils', () => {
describe('deepClone', () => {
it('should create an object with the exact same value', () => {
// Given
let input = {
const input = {
foo: {
bar: 'baz'
}
bar: 'baz',
},
};
// When
let actual = utils.deepClone(input);
const actual = utils.deepClone(input);
// Then
expect(actual.foo.bar).toEqual('baz');
});
it('should not change the initial object', () => {
// Given
let input = {
const input = {
foo: {
bar: 'baz'
}
bar: 'baz',
},
};
// When
let actual = utils.deepClone(input);
const actual = utils.deepClone(input);
input.foo.bar = 42;
// Then
expect(input.foo.bar).toEqual(42);
expect(actual.foo.bar).toNotEqual(42);
expect(actual.foo.bar).not.toEqual(42);
expect(actual.foo.bar).toEqual('baz');
});
});

View file

@ -85,29 +85,28 @@ const templates = {
`,
searchBox: `
<form novalidate="novalidate" onsubmit="return false;" class="searchbox">
<div role="search" class="searchbox__wrapper">
<input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input">
<button type="submit" title="Submit your search query." class="searchbox__submit" >
<svg width=12 height=12 role="img" aria-label="Search">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
</svg>
</button>
<button type="reset" title="Clear the search query." class="searchbox__reset hide">
<svg width=12 height=12 role="img" aria-label="Reset">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
</svg>
</button>
</div>
<div role="search" class="searchbox__wrapper">
<input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input"/>
<button type="submit" title="Submit your search query." class="searchbox__submit" >
<svg width=12 height=12 role="img" aria-label="Search">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
</svg>
</button>
<button type="reset" title="Clear the search query." class="searchbox__reset hide">
<svg width=12 height=12 role="img" aria-label="Reset">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
</svg>
</button>
</div>
</form>
<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"/></symbol>
<symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"/></symbol>
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"></symbol>
<symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"></symbol>
</svg>
</div>
`
`,
};
export default templates;

View file

@ -1,6 +1,6 @@
import $ from './zepto.js';
let utils = {
const utils = {
/*
* Move the content of an object key one level higher.
* eg.
@ -29,7 +29,7 @@ let utils = {
if (typeof object[property] !== 'object') {
return object;
}
let newObject = $.extend({}, object, object[property]);
const newObject = $.extend({}, object, object[property]);
delete newObject[property];
return newObject;
},
@ -65,7 +65,7 @@ let utils = {
* @throws Error when one of the element does not have the specified property
*/
groupBy(collection, property) {
let newCollection = {};
const newCollection = {};
$.each(collection, (index, item) => {
if (item[property] === undefined) {
throw new Error(`[groupBy]: Object has no key ${property}`);
@ -83,7 +83,7 @@ let utils = {
});
return newCollection;
},
/*
/*
* Return an array of all the values of the specified object
* eg.
* values({
@ -99,7 +99,7 @@ let utils = {
values(object) {
return Object.keys(object).map(key => object[key]);
},
/*
/*
* Flattens an array
* eg.
* flatten([1, 2, [3, 4], [5, 6]])
@ -109,19 +109,19 @@ let utils = {
* @return {array}
*/
flatten(array) {
let results = [];
array.forEach((value) => {
const results = [];
array.forEach(value => {
if (!Array.isArray(value)) {
results.push(value);
return;
}
value.forEach((subvalue) => {
value.forEach(subvalue => {
results.push(subvalue);
});
});
return results;
},
/*
/*
* Flatten all values of an object into an array, marking each first element of
* each group with a specific flag
* eg.
@ -151,15 +151,14 @@ let utils = {
* @return {array}
*/
flattenAndFlagFirst(object, flag) {
let values = this.values(object).map(collection => {
return collection.map((item, index) => {
item[flag] = (index === 0);
const values = this.values(object).map(collection =>
collection.map((item, index) => {
item[flag] = index === 0;
return item;
});
});
}));
return this.flatten(values);
},
/*
/*
* Removes all empty strings, null, false and undefined elements array
* eg.
* compact([42, false, null, undefined, '', [], 'foo']);
@ -169,7 +168,7 @@ let utils = {
* @return {array}
*/
compact(array) {
let results = [];
const results = [];
array.forEach(value => {
if (!value) {
return;
@ -197,18 +196,22 @@ let utils = {
* @return {string}
**/
getHighlightedValue(object, property) {
if (object._highlightResult
&& object._highlightResult.hierarchy_camel
&& object._highlightResult.hierarchy_camel[property]
&& object._highlightResult.hierarchy_camel[property].matchLevel
&& object._highlightResult.hierarchy_camel[property].matchLevel !== 'none'
&& object._highlightResult.hierarchy_camel[property].value) {
if (
object._highlightResult &&
object._highlightResult.hierarchy_camel &&
object._highlightResult.hierarchy_camel[property] &&
object._highlightResult.hierarchy_camel[property].matchLevel &&
object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' &&
object._highlightResult.hierarchy_camel[property].value
) {
return object._highlightResult.hierarchy_camel[property].value;
}
if (object._highlightResult
&& object._highlightResult
&& object._highlightResult[property]
&& object._highlightResult[property].value) {
if (
object._highlightResult &&
object._highlightResult &&
object._highlightResult[property] &&
object._highlightResult[property].value
) {
return object._highlightResult[property].value;
}
return object[property];
@ -234,9 +237,11 @@ let utils = {
* @return {string}
**/
getSnippetedValue(object, property) {
if (!object._snippetResult
|| !object._snippetResult[property]
|| !object._snippetResult[property].value) {
if (
!object._snippetResult ||
!object._snippetResult[property] ||
!object._snippetResult[property].value
) {
return object[property];
}
let snippet = object._snippetResult[property].value;
@ -249,7 +254,7 @@ let utils = {
}
return snippet;
},
/*
/*
* Deep clone an object.
* Note: This will not clone functions and dates
* @param {object} object Object to clone
@ -257,7 +262,7 @@ let utils = {
*/
deepClone(object) {
return JSON.parse(JSON.stringify(object));
}
},
};
export default utils;

View file

@ -1,41 +0,0 @@
/* eslint-env mocha */
global.ddescribe = describe.only;
global.xdescribe = describe.skip;
global.iit = it.only;
global.xit = it.skip;
/**
* Runs `runFunction` only when `escapeFunction` returns true. Timeout after
* `escapeTime`ms.
* @function waitForAndRun
* @param {function} escapeFunction Function to wait for. Once it returns
* `true`, we execute `runFunction`
* @param {function} runFunction Function to run once `escapeFunction` returns
* `true.
* @param {number} escapeTime Time (in ms) after which we timeout.
* @returns {void}
*/
function waitForAndRun(escapeFunction, runFunction, escapeTime) {
// check the escapeFunction every millisecond so as soon as it is met we can escape the function
var interval = setInterval(function() {
if (escapeFunction()) {
clearMe();
runFunction();
}
}, 1);
// in case we never reach the escapeFunction, we will time out
// at the escapeTime
var timeOut = setTimeout(function() {
clearMe();
runFunction();
}, escapeTime);
// clear the interval and the timeout
function clearMe() {
clearInterval(interval);
clearTimeout(timeOut);
}
}
module.exports = {
waitForAndRun
};

View file

@ -1 +0,0 @@
--compilers js:babel/register

View file

@ -1,32 +1,29 @@
import webpack from 'webpack';
import {join} from 'path';
import { join } from 'path';
export default {
entry: './index.js',
devtool: 'source-map',
output: {
path: './dist/cdn',
path: join(__dirname, 'dist/cdn'),
filename: 'docsearch.js',
library: 'docsearch',
libraryTarget: 'umd'
libraryTarget: 'umd',
},
module: {
loaders: [{
test: /\.js$/, exclude: /node_modules/, loader: 'babel'
}]
},
resolve: {
fallback: [join(__dirname, '..', 'node_modules')]
},
// same issue, for loaders like babel
resolveLoader: {
fallback: [join(__dirname, '..', 'node_modules')]
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
],
};

View file

@ -1,35 +1,24 @@
import path from 'path';
import { join } from 'path';
export default {
entry: './dev/app.js',
devtool: 'source-map',
output: {
path: './dev/',
filename: 'bundle.js'
path: join(__dirname, 'dev/'),
filename: 'bundle.js',
},
module: {
loaders: [{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'dev'),
path.resolve(__dirname, 'scripts')
], loader: 'babel'
}]
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
],
},
devServer: {
contentBase: 'dev/',
host: '0.0.0.0',
compress: true
compress: true,
},
// when module not found, find locally first
// helps fixing the npm link not working with webpack
// http://stackoverflow.com/a/33722844/147079
resolve: {
fallback: [path.join(__dirname, '..', 'node_modules')]
},
// same issue, for loaders like babel
resolveLoader: {
fallback: [path.join(__dirname, '..', 'node_modules')]
}
};

View file

@ -1,40 +1,14 @@
import webpack from 'webpack';
import {join} from 'path';
import baseConfig from './webpack.config.jsdelivr.babel';
import { join } from 'path';
export default {
entry: './index.js',
devtool: 'source-map',
output: {
path: './dist/cdn',
filename: 'docsearch.js',
library: 'docsearch',
libraryTarget: 'umd'
},
module: {
loaders: [{
test: /\.js$/, exclude: /node_modules/, loader: 'babel'
}]
},
...baseConfig,
devServer: {
contentBase: 'dist/cdn',
contentBase: join(__dirname, 'dist/cdn'),
host: '0.0.0.0',
compress: true
compress: true,
hot: true,
inline: true,
noInfo: true,
},
// when module not found, find locally first
// helps fixing the npm link not working with webpack
// http://stackoverflow.com/a/33722844/147079
resolve: {
fallback: [join(__dirname, '..', 'node_modules')]
},
// same issue, for loaders like babel
resolveLoader: {
fallback: [join(__dirname, '..', 'node_modules')]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]
};

4184
yarn.lock

File diff suppressed because it is too large Load diff