README
WOWD Components
Custom components for injecting into takomaradio.org.
Pre-requisites
This project was developed with NPM 6 and Node 8.
Ensure these are installed with node --version
and npm --version
.
Development
When building for the first time or if dependencies have changed, run
npm install
To develop,
npm run watch
Starts a development server at localhost:8080
.
There are three pages to mimic the three pages on the real site:
- http://localhost:8080/shows
- http://localhost:8080/schedule
- http://localhost:8080/djs
These pages can be used to approximate the takomaradio.org Squarespace site.
Build
npm run build
bundles javascript and css into /dist
. These files can be uploaded to Squarespace as attachements (use the link to file feature) and injected in custom header and code injection.
A global, WOWDComponents
is attached to window
and contains render functions.
Code blocks on the website can call these render functions to render the components.
For example, this code block renders the Shows page
<div id="archive-container"> </div>
<script>
var container = document.getElementById('archive-container');
WOWDComponents.renderArchives(container);
</script>
Release
To release a new version run npm version
to bump the version number and create a commit.
Push this commit.
Then run npm run publish-please
to build and publish a version to npm.
To include the changes into the takomaradio.org website, follow the instructions in the template's README.
Directory structure
The files and directories in src
are strictly organized into four standard directories. The contents of each directory are limited.
screens
- Contains only sub-directories named for full pages in the UI. If pages have a hierarchy, those sub-directories can contain anotherscreens
folder for the pages in the hierarchy.- screens - Dj - Shows - screens - Episode - Show
components
- Contains only sub-directories named for UI elements that relate to the screen of the parent directory. A component's subdirectory should contain anindex.jsx
file for the component and aComponentName.less
file for styles. If the component has a higher-order connecting component to maintain state, that is in theindex.jsx
file, andComponentName.jsx
is a pure underlying component. If there is only one file, a directory is not needed.- components - Schedule - index.jsx // Manages state, loades data from the API - Schedule.jsx // A pure React component that renders a Schedule - Schedule.less // styles used by Schedule.jsx
utils
- Contains only files that export utility functions, objects, or constants. May contain any subdirectories to organize the utilities.shared
- A special type of directory, configured in Webpack to make its contents easily importable by decendants in the hierarchy. When importing, webpack will automatically look up the tree in shared folders to find a match, so instead ofimport ../../shared/utils/myUtil
, justimport 'utils/myUtil'
will suffice.shared
can containcomponents
,screens
orutils
.shared
directories can exist on any level to make contents available below that level.- The top-level
src/shared
directory contains code not specific to WOWD, such as a generic calendar layout component with no knowledge of radio show data, a generic track manager, and types to store date and time data. Anything at this level could potentially be moved out to another repository and npm package. src/wowd/shared
contains components and utils used on many screens that are specific to WOWD such as a "show card", a play button, data types for Shows, Djs and Playlists, and an API client.
- The top-level
Frameworks and patterns
React / state management
This project is based on React.
React is often paired with a flux implementation, but that was overkill for this project since there is very litte state and almost no shared state. eventemitter3
is used in lieu of flux to notify components of changing state. The only place this is used is between the TrackManager and PlayButton for when playing state changes or the active track changes.
All other data is loaded directly by a higher order component which stores it in React state.
LESS
LESS CSS (lesscss.org) is used for styles with Webpack's CSS Modules. The tl;dr of this is: 1) All less files can be imported into javascript as objects and 2) All the class names within a :local
block in the less file, which should be the entire less file, gets replace with a random string. The exported javascript object is a map from the original class name to the randomized class name.
MyGreatComponent.less
:local {
.myGreatClass {
color: beige;
}
}
MyGreatComponent.jsx
import stylesheet from './MyGreatComponent.less'; // { 'myGreatClass' : 'MyGreatComponent-myGreatClass-x1f2'}
export <div className={stylesheet.myGreatClass} />;
This keeps styles local to a component, prevents them from being used elsewhere unintentionally, and allows for using common classnames like .body
or .title
without fear of duplication.
Code style
This project follows Squarespace's JavaScript Styles. Rather than write a Style Guide, I refer to the Squarespace .eslintrc, which has been imported into this project.
npm run lint
will find style errors, and
npm run lint-fix
will fix many of them.
lint errors will be automatically fixed when saving changes while running npm run watch
as well.
Types
This project uses Flow to add static type checking to Javascript.
All files should begin with the comment //@flow
to enable type checking unless there is a compelling reason to turn off type checking.
Run
npm run flow
to check for type errors. It is recommended to install Flow integration into your editor.
Updating Flow's libdefs
When dependencies are updated, type definities for third-party libraries must also be updated.
npm run install-libdefs
Sometimes the new libdefs are not backwards compatible, so Flow itself may also need to be upgraded at this time.