From the root of the repo run the following:
yarn
yarn build
cd packages/extension-browser
To rebuild just the browser extension you can
yarn build
from /packages/extension-browser
.
To locally test your changes you will have to sideload the extension.
The generated files are under "dist/bundle/"
.
Running the release build command will generate zip files
for both Chromium-based browsers and Firefox, found under
dist/chromium/
and dist/firefox/
respectively.
yarn build-release-packages
These are the packages that will be published to the stores. To test them you can sideload them using the same method as described earlier.
To know what dependencies are being bundled in the extension you can run
the following from /packages/extension-browser
:
yarn webpack-stats
This will generate a (big) stats.json
file.
Go to webpack visualizer or a similar tool and drop that file there to explore all the dependencies in the package.
The browser extension includes components which collaborate across different extension contexts in order to instantiate and analyze a site. These are:
-
Devtools page
"src/devtools/devtools.(html|ts)"
- Creates the devtools panel
-
Devtools panel
"src/devtools/panel.(html|tsx)"
,"src/devtools/utils/"
, and "src/devtools/views/
"- Shows UI to the user and responds to user input
- Sends messages to the background script to start/stop scans
- Forwards network requests to the background script during a scan
- Displays results received from the background script
-
Background script
"src/background-script.ts"
- Listens for messages from the devtools panel to start/stop scans
- Injects the content script into a target page during a scan
- Forwards network requests from the devtools panel to the content script
- Forwards results from the content script to the devtools panel
-
Content script
"src/content-script/(webhint.ts|connector.ts|formatter.ts)"
- Listens for configuration and network requests from background script
- Contains a bundled version of
hint
and related dependencies - Forwards network requests to bundled version of
hint
- Custom
connector
generateselement::*
events from the mirror DOM - Custom
formatter
forwards results to the background script
The UI layer of the devtools panel is organized into components using React Hooks. Each component's styles are isolated using CSS Modules.
A build-time design system can be specified using build --env.design=fluent
or build --env.design=photon
(default is fluent
). Predefined designed
systems are also already associated with release builds (fluent
for Chromium
and photon
for Firefox).
At runtime the current design system can be switched by pressing CTRL+ALT+D
.
The extension supports multiple design systems, currently Fluent and Photon, with a light and dark theme for each. Each component can optionally have a design-specific stylesheet if needed.
import * as fluent from './component.fluent.css';
import * as photon from './component.photon.css';
const Component = () => {
const styles = useCurrentDesignStyles({ fluent, photon });
return <div className={styles.root} />;
};
However most differences between designs are defined in the top-level App
component using CSS variables. If all you need to customize is a color,
you should edit or add a CSS variable here and consume it in the unified
stylesheet for your component.
/* app.fluent.css */
.root {
--my-color: #00d;
}
/* app.photon.css */
.root {
--my-color: #00c;
}
/* component.css */
.root {
color: var(--my-color);
}
/* component.tsx */
import * as styles from './component.css';
const Component = () => {
return <div className={styles.root} />;
};
Note that .root
here has different, scoped meanings in each stylesheet
due to the use of CSS Modules. Each one refers to the root of the component
the stylesheet is associated with and will be transformed based on the filename
of the stylesheet by the build process. The above example might look something
like the following at runtime:
.app-fluent_root_xT34s {
--my-color: #00d;
}
.app-photon_root_zSn4c {
--my-color: #00c;
}
.component_root_ck9Ns {
color: var(--my-color);
}
<div class="app-fluent_root_xT34s">
<div class="component_root_ck9Ns"></div>
</div>
Since dark theme typically only results in color changes, it is handled
almost entirely in the stylesheet for the root App
component. However
a custom React Hook useCurrentTheme
is available that can be accessed
from any component to determine the current theme if needed. In most
cases you'd customize colors like this:
/* app.fluent.css */
.root[data-theme='dark'] {
--my-color: #004;
}
/* app.photon.css */
.root[data-theme='dark'] {
--my-color: #003;
}
Declaring a new design system starts by adding a new entry to the
DesignSystem
enum
in "src/devtools/utils/themes.ts"
. Afterward you must
add a stylesheet for that design system to every component which declares
multiple designs before the build will pass. Each of those stylesheets must
also declare the same classes present in the other design systems for a given
component.
enum DesignSystems {
fluent = 'fluent',
photon = 'photon'
}
The content script controls which part of webhint are included as part of the
browser extension. It also controls plumbing data from the browser such as
network requests, DOM details, and results from evaluating script, back into
the bundled hint
instance.
Just add the appropriate @hint/hint-*
package as a devDependency
in
package.json
. The build script "scripts/import-hints.js"
will take care of
the rest:
"devDependencies": {
"@hint/hint-new": "^1.0.0"
}
Add the appropriate @hint/parser-*
package as a devDependency
in
package.json
and edit "content-script/webhint.ts"
to both import the
parser and include it in the Configuration
and HintResources
further
down the file:
import NewParser from '@hint/parser-new';
// ...
const config: Configuration = {
// ...
parsers: ['new']
};
// ...
const resources: HintResources = {
// ...
parsers: [
// ...
NewParser as any
]
};