Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: native constructible stylesheets #30

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
8 changes: 8 additions & 0 deletions .changeset/warm-tomatoes-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"esbuild-plugin-lit-css": minor
"@pwrs/lit-css": minor
"lit-css-loader": minor
"rollup-plugin-lit-css": minor
---

Adds `native` option to export Constructible StyleSheets.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
test/*/expected/**/*.js
test/*/native/input.js
packages/*/*.js
packages/*/*.cjs
packages/*/*.js.map
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
cache: npm

- name: Install packages
run: sudo npm ci --prefer-offline
run: npm ci --prefer-offline

- name: Lint
run: npm run lint
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
cache: npm

- name: Install packages
run: sudo npm ci --prefer-offline
run: npm ci --prefer-offline

- name: Test
run: npm test
Expand Down
17,928 changes: 8,933 additions & 8,995 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@
"@babel/preset-env": "^7.17.10",
"@changesets/cli": "^2.22.0",
"@microsoft/fast-element": "^1.10.0",
"@pwrs/eslint-config": "^0.0.25",
"@pwrs/eslint-config": "^0.0.26",
"@rollup/plugin-alias": "^3.1.9",
"@types/uglifycss": "0.0.7",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"acorn-import-assertions": "^1.7.6",
"arraybuffer-to-string": "^1.0.2",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.1.0",
"esbuild": "^0.14.38",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "^8.26.0",
"eslint-plugin-jsdoc": "^39.5.0",
"esm": "^3.2.0",
"globby": "^13.1.1",
"lit": "^2.2.3",
Expand Down
30 changes: 30 additions & 0 deletions packages/esbuild-plugin-lit-css/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ In the mean time, enjoy importing your CSS into your component files.
| ----------- | -------------------------------------------------------------------------------------- | ----------- |
| `filter` | RegExp of file names to apply to | `/\.css$/i` |
| `uglify` | Boolean or Object of [uglifycss](https://www.npmjs.com/package/uglifycss#api) options. | `false` |
| `native` | Boolean switch, when true, plugin constructs a native `CSSStyleSheet` object. | `false` |
| `specifier` | Package to import `css` from | `lit` |
| `tag` | Name of the template-tag function | `css` |
| `transform` | Optional function (sync or async) which transforms css sources (e.g. postcss) | `x => x` |
Expand Down Expand Up @@ -74,6 +75,35 @@ class CSSInCSS extends LitElement {
}
```

### Native Constructible StyleSheets

If you would like to try the **experimental** native Constructible StyleSheets feature,
set the `native: true` option. Then this plugin becomes a build-time prollyfill for native CSS modules.

```js
plugins: [
litCssPlugin({ native: true }),
],
```

Then be sure to assert your import types in your source files.

```ts
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

import style from './css-in-css.css' assert { type: 'css' };

@customElement('css-in-css')
class CSSInCSS extends LitElement {
static readonly styles = [style];

render() {
return html`<h1>It's Lit!</h1>`;
}
}
```

### Usage with FAST

```js
Expand Down
40 changes: 39 additions & 1 deletion packages/lit-css-loader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ In the mean time, enjoy importing your CSS into your component files.
| `include` | Array of glob of files to include. | `['**/*.css']` |
| `exclude` | Array of glob of files to exclude. | `undefined` |
| `uglify` | Boolean or Object of [uglifycss](https://www.npmjs.com/package/uglifycss#api) options. | `false` |
| `native` | Boolean switch, when true, plugin constructs a native `CSSStyleSheet` object. | `false` |
| `specifier` | Package to import `css` from | `lit` |
| `tag` | Name of the template-tag function | `css` |
| `transform` | Optional function (sync or async) which transforms css sources (e.g. postcss) | `x => x` |
| `transform` | Optional function (sync or async) which transforms css sources (e.g. postcss) | `x => x` |

## Usage

Expand Down Expand Up @@ -65,6 +66,43 @@ export class extends LitElement {
}
```

### Native Constructible StyleSheets

If you would like to try the **experimental** native Constructible StyleSheets feature,
set the `native: true` option. Then this plugin becomes a build-time prollyfill for native CSS modules.

```js
module: {
rules: [
{
test: /\.css$/,
loader: 'lit-css-loader',
options: {
native: true
}
}
]
}
```

Then be sure to assert your import types in your source files.

```ts
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

import style from './css-in-css.css' assert { type: 'css' };

@customElement('css-in-css')
class CSSInCSS extends LitElement {
static readonly styles = [style];

render() {
return html`<h1>It's Lit!</h1>`;
}
}
```

### Usage with Sass, Less, PostCSS, etc.

To load scss files:
Expand Down
29 changes: 25 additions & 4 deletions packages/lit-css/lit-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,26 @@ export interface Options {
* @return Transformed, standard CSS
*/
transform?(source: string, meta: Meta): string|Promise<string>;
/**
* When true, lit-css will output a native Constructible Style Sheet object.
* `native: true` implies no `tag` and no `specifier`.
* In other words, those options are ignored when using native constructors.
*/
native?: boolean;
}

function constructNative(cssContent: string): string {
return `export const sheet = new CSSStyleSheet();
sheet.replaceSync(\`${cssContent}\`);
export default sheet;
`;
}

function constructTagged(cssContent: string, tag: string, specifier: string) {
return `import {${tag}} from '${specifier}';
export const styles = ${tag}${stringToTemplateLiteral(cssContent)};
export default styles;
`;
}

export async function transform({
Expand All @@ -50,13 +70,14 @@ export async function transform({
specifier = 'lit',
tag = 'css',
uglify = false,
native = false,
transform = x => x,
}: Options): Promise<string> {
const css = await transform(source, { filePath });
const uglifyOptions = typeof uglify === 'object' ? uglify : undefined;
const cssContent = !uglify ? css : processString(css, uglifyOptions);
return `import {${tag}} from '${specifier}';
export const styles = ${tag}${stringToTemplateLiteral(cssContent)};
export default styles;
`;
if (native)
return constructNative(cssContent);
else
return constructTagged(cssContent, tag, specifier);
}
41 changes: 41 additions & 0 deletions packages/rollup-plugin-lit-css/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ In the mean time, enjoy importing your CSS into your component files.
| ----------- | -------------------------------------------------------------------------------------- | -------------- |
| `include` | Array of glob of files to include. | `['**/*.css']` |
| `exclude` | Array of glob of files to exclude. | `undefined` |
| `native` | Boolean switch, when true, plugin constructs a native `CSSStyleSheet` object. | `false` |
| `uglify` | Boolean or Object of [uglifycss](https://www.npmjs.com/package/uglifycss#api) options. | `false` |
| `specifier` | Package to import `css` from | `lit` |
| `tag` | Name of the template-tag function | `css` |
Expand Down Expand Up @@ -74,6 +75,46 @@ class CSSInCSS extends LitElement {
}
```

### Native Constructible StyleSheets

If you would like to try the **experimental** native Constructible StyleSheets feature,
set the `native: true` option. Then this plugin becomes a build-time prollyfill for native CSS modules.
You must use the `acorn-import-assertions` acorn plugin, or rollup
will choke on your import assertions:

```js
import { importAssertions } from 'acorn-import-assertions';
import litcss from 'rollup-plugin-lit-css';

export default {
// ... other rollup options here ...
acornInjectPlugins: [importAssertions],
plugins: [
litcss({ include: 'components/**/*.css', native: true })
]
}
```

Then be sure to assert your import types in your source files.

```ts
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

import style from './css-in-css.css' assert { type: 'css' };

@customElement('css-in-css')
class CSSInCSS extends LitElement {
static readonly styles = [style];

render() {
return html`<h1>It's Lit!</h1>`;
}
}
```



### Usage with FAST

```js
Expand Down
11 changes: 11 additions & 0 deletions test/esbuild-plugin-lit-css/expected/native/native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// test/😁-FIXTURES/native/styles.css
var sheet = new CSSStyleSheet();
sheet.replaceSync(`html {
display: block;
}
`);
var styles_default = sheet;
export {
styles_default as default,
sheet
};
6 changes: 6 additions & 0 deletions test/lit-css-loader/expected/native/native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const sheet = new CSSStyleSheet();
sheet.replaceSync(`html {
display: block;
}
`);
export default sheet;
7 changes: 7 additions & 0 deletions test/rollup-plugin-lit-css/expected/native/native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const sheet = new CSSStyleSheet();
sheet.replaceSync(`html {
display: block;
}
`);

export { sheet as default, sheet };
2 changes: 2 additions & 0 deletions test/rollup-plugin-lit-css/rollup-plugin-lit-css.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import aliasPlugin from '@rollup/plugin-alias';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { rollup } from 'rollup';
import { importAssertions } from 'acorn-import-assertions';

import { run } from '../test.js';

Expand All @@ -26,6 +27,7 @@ run({
const bundle = await rollup({
input,
external: ['lit', '@microsoft/fast-element', 'snoot'],
acornInjectPlugins: [importAssertions],
plugins: [
litcss(options),
...additionalPlugins,
Expand Down
6 changes: 6 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export async function run({ name, dir, getCode }) {
'handles special chars in CSS',
);

assert.equal(
await getCode('native/input.js', { options: { native: true } }),
await read('native/native.js'),
'generates a native constructible stylesheet',
);

assert.equal(
await getCode('basic/input.js', { options: { uglify: true } }),
await read('basic/uglified.js'),
Expand Down
2 changes: 2 additions & 0 deletions test/😁-FIXTURES/native/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './styles.css' assert { type: 'css' };
export { sheet } from './styles.css' assert { type: 'css' };
3 changes: 3 additions & 0 deletions test/😁-FIXTURES/native/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
html {
display: block;
}