-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/issue 972 WCC JSX import plugin (#1085)
* initial implementation of JSX plugin with SSR prerender support * add bundling spec for JSX import * documentation and README.md * clean up console logs * fix up * misc PR feedback
- Loading branch information
1 parent
7ff06de
commit cb51860
Showing
18 changed files
with
406 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# @greenwood/plugin-import-jsx | ||
|
||
## Overview | ||
Enables usage of `import` syntax for loading [JSX rendering Web Components](https://merry-caramel-524e61.netlify.app/docs/#jsx) compatible with [**WCC**](https://github.com/ProjectEvergreen/wcc). (This is _**not**_ React JSX!) | ||
|
||
> This package assumes you already have `@greenwood/cli` installed. | ||
## Installation | ||
You can use your favorite JavaScript package manager to install this package. | ||
|
||
_examples:_ | ||
```bash | ||
# npm | ||
npm install @greenwood/plugin-import-jsx --save-dev | ||
|
||
# yarn | ||
yarn add @greenwood/plugin-import-jsx --dev | ||
``` | ||
|
||
## Usage | ||
Add this plugin to your _greenwood.config.js_. | ||
|
||
```javascript | ||
import { greenwoodPluginImportJsx } from '@greenwood/plugin-import-jsx'; | ||
|
||
export default { | ||
... | ||
|
||
plugins: [ | ||
greenwoodPluginImportJsx() | ||
] | ||
} | ||
``` | ||
|
||
This will then allow you to use `import` to include [WCC]() compatible JSX rendering Web Components. | ||
```js | ||
export default class FooterComponent extends HTMLElement { | ||
connectedCallback() { | ||
this.render(); | ||
} | ||
|
||
render() { | ||
return ( | ||
<footer> | ||
<h4>My Blog</h4> | ||
</footer> | ||
); | ||
} | ||
} | ||
|
||
customElements.define('app-footer', FooterComponent); | ||
``` | ||
|
||
A couple notes: | ||
- For SSR and `prerender` use cases, [follow these steps](/docs/server-rendering/#custom-imports-experimental) | ||
- For client side / browser code specifically, it is recommended to append `?type=jsx`, e.g. | ||
```js | ||
import '../path/to/footer.jsx?type=jsx'; | ||
``` | ||
|
||
> _The plan is to coalesce around [import assertions](https://github.com/ProjectEvergreen/greenwood/issues/923) in time for the v1.0 release so the same standard syntax can be used on the client and the server._ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "@greenwood/plugin-import-jsx", | ||
"version": "0.28.0-alpha.4", | ||
"description": "A Greenwood plugin to write JSX rendering Web Components compatible with WCC.", | ||
"repository": "https://github.com/ProjectEvergreen/greenwood", | ||
"homepage": "https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-import-jsx", | ||
"author": "Owen Buckley <[email protected]>", | ||
"license": "MIT", | ||
"keywords": [ | ||
"Greenwood", | ||
"JSX", | ||
"Full Stack framework", | ||
"NodeJS", | ||
"WCC" | ||
], | ||
"main": "src/index.js", | ||
"type": "module", | ||
"files": [ | ||
"src/" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"peerDependencies": { | ||
"@greenwood/cli": "^0.28.0-alpha.4" | ||
}, | ||
"dependencies": { | ||
"wc-compiler": "~0.7.0" | ||
}, | ||
"devDependencies": { | ||
"@greenwood/cli": "^0.28.0-alpha.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* | ||
* Compile Web Components rendering with JSX using wc-compiler. | ||
* | ||
*/ | ||
import escodegen from 'escodegen'; | ||
import { parseJsx } from 'wc-compiler/src/jsx-loader.js'; | ||
import { ResourceInterface } from '@greenwood/cli/src/lib/resource-interface.js'; | ||
|
||
class ImportJsxResource extends ResourceInterface { | ||
constructor(compilation, options) { | ||
super(compilation, options); | ||
this.extensions = ['jsx']; | ||
this.contentType = 'text/javascript'; | ||
} | ||
|
||
async shouldServe(url) { | ||
const { pathname } = url; | ||
|
||
return pathname.split('.').pop() === this.extensions[0] && (url.searchParams.has('type') && url.searchParams.get('type') === this.extensions[0]); | ||
} | ||
|
||
async serve(url) { | ||
// TODO refactor when WCC refactors | ||
// https://github.com/ProjectEvergreen/wcc/issues/116 | ||
const tree = parseJsx(url); | ||
const result = escodegen.generate(tree); | ||
|
||
return new Response(result, { | ||
headers: new Headers({ | ||
'Content-Type': this.contentType | ||
}) | ||
}); | ||
} | ||
} | ||
|
||
const greenwoodPluginImportJsx = (options = {}) => [{ | ||
type: 'resource', | ||
name: 'plugin-import-jsx:resource', | ||
provider: (compilation) => new ImportJsxResource(compilation, options) | ||
}]; | ||
|
||
export { greenwoodPluginImportJsx }; |
87 changes: 87 additions & 0 deletions
87
packages/plugin-import-jsx/test/cases/default/default.prerender.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Use Case | ||
* Run Greenwood with greenwoodPluginImportJsx plugin with bundling of JSX for the client side using wc-compiler. | ||
* | ||
* User Result | ||
* Should generate a static Greenwood build with JSX properly bundled. | ||
* | ||
* User Command | ||
* greenwood build | ||
* | ||
* User Config | ||
* import { greenwoodPluginImportJsx } from '@greenwood/plugin-import-jsx'; | ||
* | ||
* { | ||
* plugins: [{ | ||
* greenwoodPluginImportJsx() | ||
* }] | ||
* } | ||
* | ||
* User Workspace | ||
* package.json | ||
* src/ | ||
* components/ | ||
* footer.jsx | ||
* pages/ | ||
* index.md | ||
* templates/ | ||
* app.html | ||
*/ | ||
import chai from 'chai'; | ||
import glob from 'glob-promise'; | ||
import { JSDOM } from 'jsdom'; | ||
import path from 'path'; | ||
import { runSmokeTest } from '../../../../../test/smoke-test.js'; | ||
import { getSetupFiles, getOutputTeardownFiles } from '../../../../../test/utils.js'; | ||
import { Runner } from 'gallinago'; | ||
import { fileURLToPath, URL } from 'url'; | ||
|
||
const expect = chai.expect; | ||
|
||
describe('(Experimental) Build Greenwood With: ', function() { | ||
const LABEL = 'Import JSX Plugin for client side bundling'; | ||
const cliPath = path.join(process.cwd(), 'packages/cli/src/index.js'); | ||
const outputPath = fileURLToPath(new URL('.', import.meta.url)); | ||
let runner; | ||
|
||
before(async function() { | ||
this.context = { | ||
publicDir: path.join(outputPath, 'public') | ||
}; | ||
runner = new Runner(false, true); | ||
}); | ||
|
||
describe(LABEL, function() { | ||
before(async function() { | ||
await runner.setup(outputPath, getSetupFiles(outputPath)); | ||
await runner.runCommand(cliPath, 'build'); | ||
}); | ||
|
||
runSmokeTest(['public'], LABEL); | ||
|
||
describe('bundling JSX using ESM (import)', function() { | ||
let dom; | ||
let scripts; | ||
|
||
before(async function() { | ||
scripts = await glob.promise(path.join(this.context.publicDir, '*.js')); | ||
dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, './index.html')); | ||
}); | ||
|
||
it('should contain one bundled output file in the output directory', function() { | ||
expect(scripts.length).to.be.equal(1); | ||
}); | ||
|
||
it('should have the expected <script> tag in the <head> for the <app-footer> component', function() { | ||
const scripts = dom.window.document.querySelectorAll('head > script'); | ||
|
||
expect(scripts.length).to.equal(1); | ||
}); | ||
}); | ||
}); | ||
|
||
after(function() { | ||
runner.teardown(getOutputTeardownFiles(outputPath)); | ||
}); | ||
|
||
}); |
7 changes: 7 additions & 0 deletions
7
packages/plugin-import-jsx/test/cases/default/greenwood.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { greenwoodPluginImportJsx } from '../../../src/index.js'; | ||
|
||
export default { | ||
plugins: [ | ||
...greenwoodPluginImportJsx() | ||
] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "test-plugin-import-jsx-build-default", | ||
"type": "module", | ||
"version": "0.27.0-alpha.0" | ||
} |
15 changes: 15 additions & 0 deletions
15
packages/plugin-import-jsx/test/cases/default/src/components/footer.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export default class FooterComponent extends HTMLElement { | ||
connectedCallback() { | ||
this.render(); | ||
} | ||
|
||
render() { | ||
return ( | ||
<footer> | ||
<h4>My Blog</h4> | ||
</footer> | ||
); | ||
} | ||
} | ||
|
||
customElements.define('app-footer', FooterComponent); |
3 changes: 3 additions & 0 deletions
3
packages/plugin-import-jsx/test/cases/default/src/pages/index.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Home Page | ||
|
||
Welcome to the home page! |
12 changes: 12 additions & 0 deletions
12
packages/plugin-import-jsx/test/cases/default/src/templates/app.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<html> | ||
<head> | ||
<title>My Personal Website</title> | ||
<script type="module" src="../components/footer.jsx?type=jsx"></script> | ||
</head> | ||
|
||
<body> | ||
<page-outlet></page-outlet> | ||
<app-footer></app-footer> | ||
</body> | ||
|
||
</html> |
89 changes: 89 additions & 0 deletions
89
packages/plugin-import-jsx/test/cases/exp-build.prerender/exp-build.prerender.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Use Case | ||
* Run Greenwood with greenwoodPluginImportJsx plugin with prerendering of JSX on the server side using wc-compiler. | ||
* | ||
* User Result | ||
* Should generate a static Greenwood build with JSX properly prerendered. | ||
* | ||
* User Command | ||
* greenwood build | ||
* | ||
* User Config | ||
* import { greenwoodPluginImportJsx } from '@greenwood/plugin-import-jsx'; | ||
* | ||
* { | ||
* plugins: [{ | ||
* greenwoodPluginImportJsx() | ||
* }] | ||
* } | ||
* | ||
* User Workspace | ||
* package.json | ||
* src/ | ||
* components/ | ||
* footer.jsx | ||
* pages/ | ||
* index.md | ||
* templates/ | ||
* app.html | ||
*/ | ||
import chai from 'chai'; | ||
import glob from 'glob-promise'; | ||
import { JSDOM } from 'jsdom'; | ||
import path from 'path'; | ||
import { runSmokeTest } from '../../../../../test/smoke-test.js'; | ||
import { getSetupFiles, getOutputTeardownFiles } from '../../../../../test/utils.js'; | ||
import { Runner } from 'gallinago'; | ||
import { fileURLToPath, URL } from 'url'; | ||
|
||
const expect = chai.expect; | ||
|
||
describe('(Experimental) Build Greenwood With: ', function() { | ||
const LABEL = 'Import JSX Plugin with static pre-rendering'; | ||
const cliPath = path.join(process.cwd(), 'packages/cli/src/index.js'); | ||
const outputPath = fileURLToPath(new URL('.', import.meta.url)); | ||
let runner; | ||
|
||
before(async function() { | ||
this.context = { | ||
publicDir: path.join(outputPath, 'public') | ||
}; | ||
runner = new Runner(false, true); | ||
}); | ||
|
||
describe(LABEL, function() { | ||
before(async function() { | ||
await runner.setup(outputPath, getSetupFiles(outputPath)); | ||
await runner.runCommand(cliPath, 'build'); | ||
}); | ||
|
||
runSmokeTest(['public'], LABEL); | ||
|
||
describe('importing JSX using ESM (import)', function() { | ||
let dom; | ||
let scripts; | ||
|
||
before(async function() { | ||
scripts = await glob.promise(path.join(this.context.publicDir, '*.js')); | ||
dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, './index.html')); | ||
}); | ||
|
||
it('should contain one bundled output file in the output directory', function() { | ||
expect(scripts.length).to.be.equal(0); | ||
}); | ||
|
||
it('should have the expected content from importing values from package.json in index.html', function() { | ||
const headings = dom.window.document.querySelectorAll('app-footer footer h4'); | ||
const year = new Date().getFullYear(); | ||
|
||
expect(headings.length).to.equal(1); | ||
expect(headings[0].textContent.trim()).to.equal(`My Blog - ${year}`); | ||
}); | ||
}); | ||
}); | ||
|
||
after(function() { | ||
runner.teardown(getOutputTeardownFiles(outputPath)); | ||
}); | ||
|
||
}); |
8 changes: 8 additions & 0 deletions
8
packages/plugin-import-jsx/test/cases/exp-build.prerender/greenwood.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { greenwoodPluginImportJsx } from '../../../src/index.js'; | ||
|
||
export default { | ||
prerender: true, | ||
plugins: [ | ||
...greenwoodPluginImportJsx() | ||
] | ||
}; |
5 changes: 5 additions & 0 deletions
5
packages/plugin-import-jsx/test/cases/exp-build.prerender/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "test-plugin-import-jsx-build-prerender", | ||
"type": "module", | ||
"version": "0.27.0-alpha.0" | ||
} |
Oops, something went wrong.