Skip to content

Commit a8eefb9

Browse files
KyleBastiendherges
authored andcommitted
feat: add tsx/jsx support (#228)
Adding the ability to specify a jsx compiler option in the ng-package.json schema. This allows for libraries to bundle tsx/jsx files, and take depedencies on vendors like React components
1 parent 0fe359e commit a8eefb9

File tree

13 files changed

+226
-12
lines changed

13 files changed

+226
-12
lines changed

README.md

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,17 @@ All you have to do is create a `package.json` file and put it where you want a s
115115
One way this can be done is by mimicking the folder structure of the following example which has a testing entry point in addition to its main entry point.
116116

117117
```
118-
my_package
118+
my_package
119119
├── src
120-
| └── *.ts
121-
├── public_api.ts
122-
├── ng-package.json
120+
| └── *.ts
121+
├── public_api.ts
122+
├── ng-package.json
123123
├── package.json
124-
├── testing
124+
├── testing
125125
├── src
126-
| └── *.ts
127-
├── public_api.ts
128-
└── package.json
126+
| └── *.ts
127+
├── public_api.ts
128+
└── package.json
129129
```
130130

131131
The contents of the secondary `package.json` can be as simple as:
@@ -135,7 +135,7 @@ The contents of the secondary `package.json` can be as simple as:
135135
}
136136
```
137137

138-
No, that is not a typo. No name is required. No version is required.
138+
No, that is not a typo. No name is required. No version is required.
139139
It's all handled for you by ng-packagr!
140140
When built, the primary entry is imported with `@my/library` and the secondary entry with `@my/library/testing`.
141141

@@ -154,6 +154,29 @@ For example, the following would use `index.ts` as the secondary entry point:
154154
}
155155
```
156156

157+
##### What if I want to use React Components?
158+
159+
If you have React Components that you're using in your library, and want to use proper JSX/TSX syntax in order to
160+
construct them, you can set the `jsx` flag for your library through `ng-package` like so:
161+
162+
```json
163+
{
164+
"$schema": "../../../src/ng-package.schema.json",
165+
"lib": {
166+
"entryFile": "public_api.ts",
167+
"externals": {
168+
"react": "React",
169+
"react-dom": "ReactDOM"
170+
},
171+
"jsx": "react"
172+
}
173+
}
174+
```
175+
176+
The `jsx` flag will accept anything that `tsconfig` accepts, more information [here](https://www.typescriptlang.org/docs/handbook/jsx.html).
177+
178+
Note: Don't forget to include `react` and `react-dom` in your `externals` so that you're not bundling those dependencies.
179+
157180

158181
## Further documentation
159182

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "../../../src/ng-package.schema.json",
3+
"lib": {
4+
"entryFile": "public_api.ts",
5+
"externals": {
6+
"react": "React",
7+
"react-dom": "ReactDOM"
8+
},
9+
"jsx": "react"
10+
}
11+
}

integration/samples/jsx/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "@sample/jsx",
3+
"description": "A sample library with jsx/tsx dependencies.",
4+
"version": "1.0.0-pre.0",
5+
"private": true,
6+
"repository": "https://github.com/dherges/ng-packagr.git",
7+
"peerDependencies": {
8+
"@angular/common": "^4.1.3",
9+
"@angular/core": "^4.1.3",
10+
"@angular/router": "^4.1.3",
11+
"rxjs": "^5.0.1",
12+
"zone.js": "^0.8.4",
13+
"react": "^16.0.0",
14+
"react-dom": "^16.0.0"
15+
}
16+
}

integration/samples/jsx/public_api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './src/react-integration.component';
2+
export * from './src/react-integration.module';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Component, OnInit, AfterViewInit, ElementRef } from '@angular/core';
2+
import * as React from 'react';
3+
import * as ReactDOM from 'react-dom';
4+
5+
// Simulating the use of an external library that contains React Components
6+
class ReactLabel extends React.Component {
7+
render() {
8+
return (
9+
<label>Look JSX!</label>
10+
);
11+
}
12+
}
13+
14+
@Component({
15+
selector: 'react-integration-test',
16+
template: `
17+
<div></div>
18+
`,
19+
styles: [``]
20+
})
21+
export class AngularReactLabel implements AfterViewInit {
22+
23+
constructor(private hostRef: ElementRef) {}
24+
25+
ngAfterViewInit(): void {
26+
const hostElement = this.hostRef.nativeElement;
27+
const LabelToShow = () => (
28+
// Actual use here, might include data-binding in a real world scenario
29+
<ReactLabel></ReactLabel>
30+
);
31+
ReactDOM.render(<LabelToShow />, hostElement);
32+
}
33+
34+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { NgModule } from '@angular/core';
2+
import { CommonModule } from '@angular/common';
3+
import { AngularReactLabel } from './react-integration.component';
4+
5+
@NgModule({
6+
declarations: [ AngularReactLabel ],
7+
imports: [ CommonModule ],
8+
exports: [ AngularReactLabel ],
9+
providers: [],
10+
})
11+
export class ReactIntegrationModule {}

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
"@types/lodash": "^4.14.77",
6969
"@types/mocha": "^2.2.41",
7070
"@types/node": "^8.0.0",
71+
"@types/react": "^16.0.19",
72+
"@types/react-dom": "^16.0.2",
7173
"@types/sinon": "^2.3.0",
7274
"chai": "^4.0.1",
7375
"copyfiles": "^1.2.0",
@@ -77,6 +79,8 @@
7779
"jasmine": "^2.6.0",
7880
"json-schema-to-typescript": "^4.4.0",
7981
"mocha": "^4.0.0",
82+
"react": "^16.0.0",
83+
"react-dom": "^16.0.0",
8084
"rxjs": "^5.4.0",
8185
"sinon": "^4.0.0",
8286
"standard-version": "^4.0.0",

src/lib/model/ng-package-data.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class NgPackageData {
1515
public readonly destinationPath: string;
1616
public readonly buildDirectory: string;
1717
public readonly libExternals: any;
18+
public readonly jsxConfig?: string;
1819

1920
constructor(
2021
/**
@@ -53,6 +54,7 @@ export class NgPackageData {
5354
this.libExternals = ngPackageConfig.lib.externals;
5455
this.flatModuleFileName = ngPackageConfig.lib.flatModuleFile;
5556
this.entryFile = ngPackageConfig.lib.entryFile;
57+
this.jsxConfig = ngPackageConfig.lib.jsx;
5658
}
5759

5860
if (!this.libExternals) {

src/lib/steps/assets.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const processAssets = (src: string, dest: string): Promise<any> => {
2929
return new Promise((resolve, reject) => {
3030
debug(`processAssets ${src} to ${dest}`);
3131

32-
vfs.src([`${src}/**/*.ts`, '!node_modules/**/*', '!${dest}/**/*'])
32+
vfs.src([`${src}/**/*.ts`, `${src}/**/*.tsx`, `${src}/**/*.jsx`, '!node_modules/**/*', '!${dest}/**/*'])
3333
.pipe(inlineNg2Template({
3434
base: `${src}`,
3535
useRelativePaths: true,

src/lib/steps/ngc.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ async function prepareTsConfig(ngPkg: NgPackageData, outFile: string): Promise<v
1717

1818
tsConfig['files'] = [ ngPkg.entryFile ];
1919

20+
if (ngPkg.jsxConfig) {
21+
debug('prepareTsConfig: Applying jsx flag to tsconfig ' + ngPkg.jsxConfig);
22+
tsConfig['compilerOptions']['jsx'] = ngPkg.jsxConfig;
23+
}
24+
2025
await writeJson(outFile, tsConfig);
2126
}
2227

0 commit comments

Comments
 (0)