When we refer to "standard video.js plugins" we are not referring to any official, codified standard (e.g. ECMAScript or HTML5). Rather, we are referring to the rules used internally at Brightcove in developing both open-source and proprietary plugins for video.js.
These rules are by no means required for community plugins. You can write plugins in whichever way you choose. However, these rules are recommended, as we want to foster consistency within the video.js ecosystem.
This document and the Yeoman generator it is part of are provided as open-source for the good of the community. If you don't agree with these standards, by all means follow your preferences in your plugin projects!
All standard video.js plugins must:
- ...be npm packages.
- ...have automation available through npm scripts.
- ...implement the core set of npm scripts.
- ...be written in ES6 and pass
videojs-standard
linting. - ...have tests.
- ...never check build artifacts into the repository.
All standard video.js plugins must be npm packages.
Plugins should be as self-contained as possible, so the only dependency ("dependencies"
in package.json
) by default is video.js, which is shimmed using browserify-shim
.
Development dependencies ("devDependencies"
in package.json
) will include many packages related to developing, building, and testing a standard video.js plugin.
Folder/Filename | Optional? | Generated? | Description |
---|---|---|---|
dist/ |
Created during builds, ignored by Git. | ||
dist-test/ |
Created during test builds, ignored by Git. | ||
docs/ |
✓ | Any documentation beyond README.md . |
|
es5/ |
Babel-compiled src/ scripts. |
||
lang/ |
✓ | ? | Any JSON language files for the plugin. |
scripts/ |
✓ | Scripts used by npm; not part of the source code! | |
src/ |
✓ | All source code. | |
src/scss/ |
✓ | Sass source code/partials. | |
src/js/ |
✓ | JavaScript source code. | |
src/plugin.scss |
✓ | ? | Sass entry point. |
src/plugin.js |
✓ | Browserify entry point. | |
test/ |
✓ | Unit tests. | |
test/karma/ |
✓ | Karma configuration files. | |
test/plugin.test.js |
✓ | Browserify entry point. | |
.editorconfig |
✓ | ||
.gitignore |
✓ | ||
.npmignore |
✓ | ||
bower.json |
✓ | ? | |
CHANGELOG.md |
✓ | ✓ | May be removed if not desired. |
CONTRIBUTING.md |
✓ | ? | Not present in closed-source plugins. |
index.html |
✓ | ✓ | An example of usage of the plugin. This can be used with GitHub pages as well. |
LICENSE |
✓ | ? | Defaults to MIT . |
package.json |
✓ | ||
README.md |
✓ | Documents which version(s) of video.js the plugin supports. Explains how to build/test. |
- ✓: The file/directory is not required to meet the rules in this document.
Bear in mind, that multiple runs of the generator will prompt you for each conflicting file that exists before overwriting!
- ✓: The file/directory is always generated by the generator.
- ?: The file/directory may be generated, depending on options.
- Otherwise, the file is never generated.
All automation for a standard video.js plugin must be available through npm scripts.
The generator provides npm script automation for all aspects of plugin development. There is no need for a third-party build tool.
However, some developers may prefer to implement their build process with a tool like Gulp or Grunt and this is an accepted practice provided the core set of npm scripts are aliased to the appropriate command for your build tool. For example, if you're using grunt
, your package.json
might have:
"scripts": {
"build": "grunt",
"build:js": "grunt js"
}
There are many good reasons to standardize on npm scripts:
- npm provides a unified interface while keeping implementation choices up to the individual developer or team.
- Where a separate build tool is preferred, npm scripts can easily act as aliases to build tasks (e.g.,
"start": "gulp start-server"
). - npm is a common denominator (far more than build tools); so, CI servers, contributors, and other tools can use npm without worrying about the underlying tool.
- Consistent npm script naming means contributors don't have to learn a new build tool or new set of commands when moving between plugin projects, lowering the barrier to contributions.
All standard video.js plugins must implement the core set of npm scripts.
All names are lower-case and use colons (:
) as sub-task separators (multiple colons separate multiple levels of sub-tasks). Other scripts (e.g., sub-sub-tasks and pre*
/post*
scripts) will be created as well, but these are not documented here as they are not considered core scripts and are subject to change.
npm Script | Optional | Description |
---|---|---|
build |
Runs all build sub-tasks. | |
build:css |
✓ | Builds the Sass entry point. |
build:js |
Builds the Browserify entry point. | |
build:lang |
✓ | Builds language files. |
build:test |
Builds the test Browserify entry point. | |
clean |
Cleans up all build artifacts. | |
docs |
✓ | Performs documentation tasks. |
lint |
Lints all .js ES6 source file(s) using videojs-standard . |
|
start |
Starts a development server at port 9999 (or closest open port) and runs watch . |
|
test |
Runs lint , builds tests, and runs tests in available browsers. |
|
test:* |
✓ | Browser-specific tests (e.g. test:firefox ). |
watch |
Watches everything and runs appropriate tasks. | |
watch:css |
✓ | Triggers a build when the Sass entry point changes (without banner comment). |
watch:js |
Triggers a build when the Browserify entry point changes (without banner comment or minification). | |
watch:test |
Triggers a build when the test entry point changes. | |
version |
Includes preversion and postversion scripts. Bumps the package version and creates a tag. Special handling if Bower support is enabled! |
All standard video.js plugins must pass videojs-standard
linting.
In an effort to reduce guess work, improve maintainability, avoid stylistic bikeshedding, and simplify the code review process, we have a linter based on the popular standard project, named videojs-standard.
Its coding conventions are enforced in standard video.js plugins via the npm run lint
command.
videojs-standard
assumes all code it evaluates is written in ES6. Therefore, it ignores built scripts and any script(s) which must be written in ES5.
All standard video.js plugins must have tests.
Testing is a critical element of any software project and it should be done in an environment as similar to production as possible. To that end, video.js tests should be run in a browser.
Testing is performed with QUnit as the testing framework and Karma as the runner.
All scripts containing tests must be named in the format *.test.js
The generator-provided test entry point is test/plugin.test.js
(matching src/plugin.js
). For simple plugins, this is typically sufficient.
For complex plugins with multiple modules/components, it might make sense to break up tests into multiple modules, too. How test modules are split up is really up to the developer, but the recommended practice is to have a test module for each source module. For example:
src/plugin.js :: test/plugin.test.js
src/foo.js :: test/foo.test.js
src/bar.js :: test/bar.test.js
When the build:test
script is executed, all *.test.js
files within test
and sub-directories will be built into the output script (dist-test/${pluginName}.js
).
All the test automation uses single-run Karma sessions. npm test
will launch all the matching browsers which Karma supports and run tests in them. npm run test:*
will test in a given browser (e.g. chrome
or firefox
).
During development, it may be more convenient to run your tests manually in a browser tab (i.e. not through Karma). This can be achieved easily by running a development server with npm start
and navigating to http://localhost:9999/test/
(note: the port may vary, check console output).
Standard video.js plugins may support Bower, but must never check in build artifacts to source control.
This is the easy case, but not the default in the generator. In this case, no tricky versioning workflow needs to be followed; however, tests are run before versioning and the build is run during versioning.
After the tag is created, master
is automatically pushed to origin/master
and tags are pushed to origin
. If your repository is set up differently, modify the script (or remove it if you prefer that step to be manual).
It is generally considered a best practice to not check build artifacts (dist/
etc.) into source control. However, because Bower only clones repositories and offers no mechanism for scripting, we must define a workflow for bumping versions without checking dist/
into the repository's master
history!
This assumes use of the npm version
command:
- The npm
"preversion"
script will: - Verify that the project is a Git repository and that there are not unstaged/uncommitted changes. Either condition will cause the rest of the workflow to fail.
- Run tests to enforce code quality before allowing the version to be bumped.
- npm automatically bumps the
package.json
version. - The npm
"version"
script will run: package.json
is staged, committed, and pushed. The effect of this is that thepackage.json
change exists in the history ofmaster
.- Run
npm run build
, so that the new version number gets picked up in built assets. - The
dist/
directory will be force-staged. Normally, it is ignored, but it needs to exist in the tag for Bower to install things properly. - npm automatically commits and tags. This commit will contain only the
dist/
dir (thepackage.json
bump is the parent commit). - The npm
"postversion"
script will run: master
is hard-reset to the state oforigin/master
. This avoidsdist/
being added tomaster
's history - tagged commits will be children of commits onmaster
.- Tags are pushed to
origin
.
This process results in a master
history that looks something like this:
<...> C --- V --- C --- C <...> C --- C --- V --- C --- C <...>
\ \
T T
C
: signifies a conventional commit.
V
: signifies a version bump commit.
T
: tagged commit, with dist/
included.
Open-source plugins should use the most basic publishing process available - npm publish
- which should be run after versioning. Closed-source plugins are left to their respective author(s) or organization.