Skip to content

Commit

Permalink
feat: CSS entrypoints (wxt-dev#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
aklinker1 authored Jul 21, 2023
1 parent 5b269f4 commit 044a24f
Show file tree
Hide file tree
Showing 18 changed files with 259 additions and 20 deletions.
1 change: 1 addition & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"devDependencies": {
"@types/webextension-polyfill": "^0.10.0",
"sass": "^1.64.0",
"wxt": "workspace:*"
}
}
3 changes: 3 additions & 0 deletions demo/src/entrypoints/iframe.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: red;
}
3 changes: 3 additions & 0 deletions demo/src/entrypoints/injected.content/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
color: blue;
}
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default defineConfig({
{ text: 'Background', link: '/guide/background.md' },
{ text: 'Bookmarks', link: '/guide/bookmarks.md' },
{ text: 'Content Scripts', link: '/guide/content-scripts.md' },
{ text: 'CSS', link: '/guide/css.md' },
{ text: 'Devtools', link: '/guide/devtools.md' },
{ text: 'History', link: '/guide/history.md' },
{ text: 'Newtab', link: '/guide/newtab.md' },
Expand Down
17 changes: 16 additions & 1 deletion docs/guide/content-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ When defining multiple content scripts, content script entrypoints that have the

## CSS

To include CSS with your content script, import the CSS file at the top of your entrypoint:
To include CSS with your content script, import the CSS file at the top of your entrypoint.

```
Expand All @@ -60,3 +60,18 @@ export default defineContentScript({
},
});
```

Any styles imported in your content script will be added to that content script's `css` array in your `manifest.json`:

```json
// .output/chrome-mv3/manifest.json
{
"content_scripts": [
{
"matches": ["*://google.com/*", "*://duckduckgo.com/*"],
"js": ["content-scripts/overlay.js"],
"css": ["content-scripts/overlay.css"]
}
]
}
```
41 changes: 41 additions & 0 deletions docs/guide/css.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# CSS

WXT can build CSS entrypoints individually. CSS entrypoints are always unlisted.

See [Content Script CSS](/guide/content-scripts.md#css) documentation for the recomended approach to include CSS with a content script.

:::info
If the recommended approach doesn't work for your use case, you can use any of the filename patterns below to build the styles separate from the JS and use the [`transformManifest` hook](/config.md#transformmanifest) to manually add your CSS file to the manifest.
:::

## Filenames

When a filename matches the pattern below, WXT will transform it and output it with the rest of your extension.

- `entrypoints/content.(css|scss|sass|less|styl|stylus)`
- `entrypoints/<name>.(css|scss|sass|less|styl|stylus)`
- `entrypoints/<name>/index.(css|scss|sass|less|styl|stylus)`
- `entrypoints/<name>.content.(css|scss|sass|less|styl|stylus)`
- `entrypoints/<name>.content/index.(css|scss|sass|less|styl|stylus)`

## Definition

```css
body {
/* Plain CSS file */
}
```

Follow Vite's guide to setup a preprocessor: https://vitejs.dev/guide/features.html#css-pre-processors

```sh
pnpm i sass
```

```scss
body {
h1 {
/* ...*/
}
}
```
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
"linkedom": "^0.14.26",
"minimatch": "^9.0.3",
"picocolors": "^1.0.0",
"picomatch": "^2.3.1",
"unimport": "^3.0.8",
"vite": "^4.3.9",
"vite-tsconfig-paths": "^4.2.0",
Expand All @@ -91,7 +90,6 @@
"@types/fs-extra": "^11.0.1",
"@types/lodash.merge": "^4.6.7",
"@types/node": "^20.3.1",
"@types/picomatch": "^2.3.0",
"@vitest/coverage-v8": "^0.32.2",
"lodash.merge": "^4.6.2",
"npm-run-all": "^4.1.5",
Expand Down Expand Up @@ -125,4 +123,4 @@
]
}
}
}
}
27 changes: 17 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions src/core/build/__tests__/findEntrypoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,73 @@ describe('findEntrypoints', () => {
outputDir: config.outDir,
},
],
[
'injected/index.ts',
{
type: 'unlisted-script',
name: 'injected',
inputPath: resolve(config.entrypointsDir, 'injected/index.ts'),
outputDir: config.outDir,
},
],

// unlisted-style
[
'iframe.scss',
{
type: 'unlisted-style',
name: 'iframe',
inputPath: resolve(config.entrypointsDir, 'iframe.scss'),
outputDir: config.outDir,
},
],
[
'iframe.css',
{
type: 'unlisted-style',
name: 'iframe',
inputPath: resolve(config.entrypointsDir, 'iframe.css'),
outputDir: config.outDir,
},
],

// content-script-style
[
'content.css',
{
type: 'content-script-style',
name: 'content',
inputPath: resolve(config.entrypointsDir, 'content.css'),
outputDir: resolve(config.outDir, 'content-scripts'),
},
],
[
'overlay.content.css',
{
type: 'content-script-style',
name: 'overlay',
inputPath: resolve(config.entrypointsDir, 'overlay.content.css'),
outputDir: resolve(config.outDir, 'content-scripts'),
},
],
[
'content/index.css',
{
type: 'content-script-style',
name: 'content',
inputPath: resolve(config.entrypointsDir, 'content/index.css'),
outputDir: resolve(config.outDir, 'content-scripts'),
},
],
[
'overlay.content/index.css',
{
type: 'content-script-style',
name: 'overlay',
inputPath: resolve(config.entrypointsDir, 'overlay.content/index.css'),
outputDir: resolve(config.outDir, 'content-scripts'),
},
],
])('should find entrypoint for %s', async (path, expected) => {
globMock.mockResolvedValueOnce([path]);

Expand Down
13 changes: 11 additions & 2 deletions src/core/build/buildEntrypoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
EntrypointGroup,
InternalConfig,
} from '../types';
import * as plugins from '../vite-plugins';
import * as wxtPlugins from '../vite-plugins';
import { removeEmptyDirs } from '../utils/removeEmptyDirs';
import { getEntrypointBundlePath } from '../utils/entrypoints';
import fs from 'fs-extra';
Expand Down Expand Up @@ -45,7 +45,16 @@ async function buildSingleEntrypoint(
? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}`
: entrypoint.inputPath;

const plugins: NonNullable<vite.UserConfig['plugins']> = [];
if (
entrypoint.type === 'content-script-style' ||
entrypoint.type === 'unlisted-style'
) {
plugins.push(wxtPlugins.cssEntrypoints(entrypoint, config));
}

const libMode: vite.UserConfig = {
plugins,
build: {
lib: {
entry,
Expand Down Expand Up @@ -90,7 +99,7 @@ async function buildMultipleEntrypoints(
config: InternalConfig,
): Promise<BuildStepOutput> {
const multiPage: vite.UserConfig = {
plugins: [plugins.multipageMove(entrypoints, config)],
plugins: [wxtPlugins.multipageMove(entrypoints, config)],
build: {
rollupOptions: {
input: entrypoints.reduce<Record<string, string>>((input, entry) => {
Expand Down
24 changes: 21 additions & 3 deletions src/core/build/findEntrypoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import {
PopupEntrypoint,
} from '../types';
import fs from 'fs-extra';
import picomatch from 'picomatch';
import { minimatch } from 'minimatch';
import { parseHTML } from 'linkedom';
import JSON5 from 'json5';
import { importTsFile } from '../utils/importTsFile';
import glob from 'fast-glob';
import { getEntrypointName } from '../utils/entrypoints';
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../vite-plugins/noopBackground';
import { CSS_EXTENSIONS_PATTERN } from '../utils/paths';

/**
* Return entrypoints and their configuration by looking through the project's files.
Expand All @@ -39,7 +40,7 @@ export async function findEntrypoints(
relativePaths.map(async (relativePath) => {
const path = resolve(config.entrypointsDir, relativePath);
const matchingGlob = pathGlobs.find((glob) =>
picomatch.isMatch(relativePath, glob),
minimatch(relativePath, glob),
);

if (matchingGlob == null) {
Expand Down Expand Up @@ -74,6 +75,14 @@ export async function findEntrypoints(
path,
);
break;
case 'content-script-style':
entrypoint = {
type,
name: getEntrypointName(config.entrypointsDir, path),
inputPath: path,
outputDir: resolve(config.outDir, CONTENT_SCRIPT_OUT_DIR),
};
break;
default:
entrypoint = {
type,
Expand Down Expand Up @@ -243,7 +252,7 @@ async function getContentScriptEntrypoint(
type: 'content-script',
name: getEntrypointName(config.entrypointsDir, path),
inputPath: path,
outputDir: resolve(config.outDir, 'content-scripts'),
outputDir: resolve(config.outDir, CONTENT_SCRIPT_OUT_DIR),
options,
};
}
Expand Down Expand Up @@ -278,6 +287,10 @@ const PATH_GLOB_TO_TYPE_MAP: Record<string, Entrypoint['type'] | 'ignored'> = {
'content/index.ts?(x)': 'content-script',
'*.content.ts?(x)': 'content-script',
'*.content/index.ts?(x)': 'content-script',
[`content.${CSS_EXTENSIONS_PATTERN}`]: 'content-script-style',
[`*.content.${CSS_EXTENSIONS_PATTERN}`]: 'content-script-style',
[`content/index.${CSS_EXTENSIONS_PATTERN}`]: 'content-script-style',
[`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: 'content-script-style',

'popup.html': 'popup',
'popup/index.html': 'popup',
Expand All @@ -288,7 +301,12 @@ const PATH_GLOB_TO_TYPE_MAP: Record<string, Entrypoint['type'] | 'ignored'> = {
'*.html': 'unlisted-page',
'*/index.html': 'unlisted-page',
'*.ts': 'unlisted-script',
'*/index.ts': 'unlisted-script',
[`*.${CSS_EXTENSIONS_PATTERN}`]: 'unlisted-style',
[`*/index.${CSS_EXTENSIONS_PATTERN}`]: 'unlisted-style',

// Don't warn about any files in subdirectories, like CSS or JS entrypoints for HTML files
'*/*': 'ignored',
};

const CONTENT_SCRIPT_OUT_DIR = 'content-scripts';
4 changes: 3 additions & 1 deletion src/core/types/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,9 @@ export interface GenericEntrypoint extends BaseEntrypoint {
| 'sidepanel'
| 'devtools'
| 'unlisted-page'
| 'unlisted-script';
| 'unlisted-script'
| 'unlisted-style'
| 'content-script-style';
}

export interface BackgroundEntrypoint extends BaseEntrypoint {
Expand Down
Loading

0 comments on commit 044a24f

Please sign in to comment.