Skip to content

Commit 633e4cf

Browse files
authored
Add Angular example (#35)
1 parent e762b77 commit 633e4cf

File tree

8 files changed

+411
-3
lines changed

8 files changed

+411
-3
lines changed

ci/prepare_playwright.sh

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ set -eux
99
./single_example.sh typescript vanilla_vite
1010
./single_example.sh typescript react_vite
1111
./single_example.sh typescript vue_vite
12+
./single_example.sh typescript angular_ng

ci/single_example.sh

+8-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@ fi
1212
export TYPE=$1
1313
export EXAMPLE=$2
1414

15+
export SANITISED_EXAMPLE=$EXAMPLE
16+
1517
if [[ $EXAMPLE =~ _vite$ ]]; then
1618
export PORT=5173
1719
export SERVE_CMD="npm run dev"
20+
elif [[ $EXAMPLE =~ ^angular_ng$ ]]; then
21+
export PORT=4200
22+
export SERVE_CMD="npm run start"
23+
# Angular annoyingly converts underscores to dashes
24+
export SANITISED_EXAMPLE=angular-ng
1825
else
1926
export PORT=4500
2027
export SERVE_CMD="npm run serve"
@@ -74,7 +81,7 @@ EOF
7481
cat > temp.json << EOF
7582
{
7683
"scripts": {
77-
"serve": "npm explore $EXAMPLE -- $SERVE_CMD",
84+
"serve": "npm explore $SANITISED_EXAMPLE -- $SERVE_CMD",
7885
"test": "playwright test",
7986
"test:ui": "playwright test --ui"
8087
}

ci/typescript/create_angular_ng.sh

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env bash
2+
3+
set -eux
4+
5+
export OUTPUT_DIRECTORY=../temp/typescript/angular_ng
6+
7+
mkdir -p $OUTPUT_DIRECTORY
8+
cd $OUTPUT_DIRECTORY
9+
rm -rf *
10+
11+
function merge-json() {
12+
# merge the second json file into the first.
13+
TEMP_FILE=$(mktemp)
14+
jq '. * input' $1 $2 > TEMP_FILE && mv TEMP_FILE $1
15+
}
16+
17+
# 1. Install @angular/cli
18+
npm install -g @angular/cli
19+
20+
# 2. Create Angular application
21+
ng new angular_ng --directory ./ --minimal --routing=false --skip-git --ssr=false --style=css
22+
23+
# 3. Build and serve the initial project
24+
# npm run build
25+
# # npm run start
26+
# In a web browser navigate to http://localhost:4200/
27+
28+
# 4. Add BokehJS dependency to this project. This assumes the package has been built and copied to the root directory of this repository as outlined in the top-level README.md.
29+
npm install ../../../../bokeh-bokehjs-3.8.0-dev.1.tgz
30+
31+
# 5. Create a new file src/app/bokeh-js/bokeh-js.component.ts containing a BokehJS plot component
32+
mkdir -p src/app/bokeh-js
33+
cat > src/app/bokeh-js/bokeh-js.component.ts << EOF
34+
import { Component, OnInit } from '@angular/core'
35+
import * as Bokeh from "@bokeh/bokehjs";
36+
37+
function create_bokehjs_plot(): Bokeh.Column {
38+
const source = new Bokeh.ColumnDataSource({data: { x: [0.1, 0.9], y: [0.1, 0.9], size: [40, 10] }});
39+
40+
const plot = Bokeh.Plotting.figure({
41+
title: "Example BokehJS plot", height: 500, width: 500,
42+
x_range: [0, 1], y_range: [0, 1], sizing_mode: "stretch_width",
43+
});
44+
45+
plot.scatter({ field: "x" }, { field: "y" }, {source, size: { field: "size" }});
46+
47+
const button = new Bokeh.Widgets.Button({label: "Click me to add a point", button_type: "primary"});
48+
function button_callback() {
49+
const data = source.data as any;
50+
data.x.push(Math.random());
51+
data.y.push(Math.random());
52+
data.size.push(10 + Math.random()*30);
53+
source.change.emit();
54+
}
55+
button.on_click(button_callback);
56+
57+
return new Bokeh.Column({children: [plot, button], sizing_mode: "stretch_width"});
58+
}
59+
60+
@Component({
61+
selector: 'app-bokeh-js',
62+
imports: [],
63+
template: \`<div id="target"></div>\`,
64+
styles: \`\`
65+
})
66+
67+
export class BokehJSComponent implements OnInit {
68+
ngOnInit() {
69+
console.info("BokehJS version:", Bokeh.version);
70+
Bokeh.Plotting.show(create_bokehjs_plot(), "#target");
71+
}
72+
}
73+
EOF
74+
75+
# 6. Replace src/app/app.component.ts so that it uses the BokehJSComponent
76+
cat > src/app/app.component.ts << EOF
77+
import { Component } from '@angular/core'
78+
import { BokehJSComponent } from './bokeh-js/bokeh-js.component';
79+
80+
@Component({
81+
selector: 'app-root',
82+
imports: [BokehJSComponent],
83+
template: \`<app-bokeh-js></app-bokeh-js>\`,
84+
styles: [],
85+
})
86+
87+
export class AppComponent {}
88+
EOF
89+
90+
# 7. Remove some build warnings by allowing non ESM imports by adding to angular.json
91+
cat > temp.json << EOF
92+
{
93+
"projects": {
94+
"angular_ng": {
95+
"architect": {
96+
"build": {
97+
"options": {
98+
"allowedCommonJsDependencies": [
99+
"@bokeh/bokehjs",
100+
"mathjax-full",
101+
"regl"
102+
]
103+
}
104+
}
105+
}
106+
}
107+
}
108+
}
109+
EOF
110+
merge-json angular.json temp.json
111+
rm temp.json
112+
113+
# 8. Remove bundle size limits in angular.json by setting the "budgets" to an empty array
114+
cat > temp.json << EOF
115+
{
116+
"projects": {
117+
"angular_ng": {
118+
"architect": {
119+
"build": {
120+
"configurations": {
121+
"production": {
122+
"budgets": [
123+
]
124+
}
125+
}
126+
}
127+
}
128+
}
129+
}
130+
}
131+
EOF
132+
merge-json angular.json temp.json
133+
rm temp.json
134+
135+
# 9. Rebuild and Serve the project
136+
npm run build
137+
# npm run start
138+
# In a web browser navigate to http://localhost:4200/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { Recipe } from '../../recipe';
2+
import { CommandStep, CreateFileStep, MergeJsonStep, ReplaceFileStep } from '../../step';
3+
import { baseTypeScriptExample } from './common';
4+
5+
export class AngularNgRecipe extends Recipe {
6+
constructor() {
7+
super(
8+
'typescript',
9+
'angular',
10+
'ng',
11+
'The Angular web framework includes its own builder `ng` in the `@angular/cli` package'
12+
);
13+
14+
this.add(new CommandStep(
15+
'Install `@angular/cli`',
16+
['npm install -g @angular/cli']
17+
));
18+
19+
this.add(new CommandStep(
20+
'Create Angular application',
21+
['ng new angular_ng --directory ./ --minimal --routing=false --skip-git --ssr=false --style=css']
22+
));
23+
24+
this.add(new CommandStep(
25+
'Build and serve the initial project',
26+
['npm run build', 'npm run start'],
27+
'In a web browser navigate to http://localhost:4200/',
28+
true
29+
));
30+
31+
this.add(new CommandStep(
32+
'Add BokehJS dependency to this project. This assumes the package has been built and ' +
33+
'copied to the root directory of this repository as outlined in the top-level `README.md`.',
34+
['npm install ../../../../bokeh-bokehjs-3.8.0-dev.1.tgz']
35+
));
36+
37+
this.add(new CreateFileStep(
38+
'Create a new file `src/app/bokeh-js/bokeh-js.component.ts` containing a BokehJS plot component',
39+
'src/app/bokeh-js/bokeh-js.component.ts',
40+
"import { Component, OnInit } from '@angular/core'\n" +
41+
baseTypeScriptExample.import + "\n" +
42+
baseTypeScriptExample.function + "\n" +
43+
"@Component({\n" +
44+
" selector: 'app-bokeh-js',\n" +
45+
" imports: [],\n" +
46+
' template: \\`<div id="target"></div>\\`,\n' +
47+
" styles: \\`\\`\n" +
48+
"})\n\n" +
49+
"export class BokehJSComponent implements OnInit {\n" +
50+
" ngOnInit() {\n" +
51+
" " + baseTypeScriptExample.version +
52+
" " + baseTypeScriptExample.show() +
53+
" }\n" +
54+
"}")
55+
);
56+
57+
this.add(new ReplaceFileStep(
58+
'Replace `src/app/app.component.ts` so that it uses the `BokehJSComponent`',
59+
'src/app/app.component.ts',
60+
"import { Component } from '@angular/core'\n" +
61+
"import { BokehJSComponent } from './bokeh-js/bokeh-js.component';\n\n" +
62+
"@Component({\n" +
63+
" selector: 'app-root',\n" +
64+
" imports: [BokehJSComponent],\n" +
65+
" template: \\`<app-bokeh-js></app-bokeh-js>\\`,\n" +
66+
" styles: [],\n" +
67+
"})\n\n" +
68+
"export class AppComponent {}")
69+
);
70+
71+
this.add(new MergeJsonStep(
72+
'Remove some build warnings by allowing non ESM imports by adding to `angular.json`',
73+
'angular.json',
74+
`{
75+
"projects": {
76+
"angular_ng": {
77+
"architect": {
78+
"build": {
79+
"options": {
80+
"allowedCommonJsDependencies": [
81+
"@bokeh/bokehjs",
82+
"mathjax-full",
83+
"regl"
84+
]
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}`)
91+
);
92+
93+
this.add(new MergeJsonStep(
94+
'Remove bundle size limits in `angular.json` by setting the `"budgets"` to an empty array',
95+
'angular.json',
96+
`{
97+
"projects": {
98+
"angular_ng": {
99+
"architect": {
100+
"build": {
101+
"configurations": {
102+
"production": {
103+
"budgets": [
104+
]
105+
}
106+
}
107+
}
108+
}
109+
}
110+
}
111+
}`)
112+
);
113+
114+
this.add(new CommandStep(
115+
'Rebuild and Serve the project',
116+
['npm run build', 'npm run start'],
117+
'In a web browser navigate to http://localhost:4200/'
118+
));
119+
}
120+
}

recipes/src/recipes/typescript/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './angular_ng_recipe';
12
export * from './react_vite_recipe';
23
export * from './vanilla_rspack_recipe';
34
export * from './vanilla_vite_recipe';

recipes/src/recipes/typescript/react_vite_recipe.ts

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export class ReactViteRecipe extends Recipe {
4242
export default App`)
4343
);
4444

45-
4645
this.add(new ReplaceFileStep(
4746
'Remove CSS lines from `src/main.tsx` by replacing it',
4847
'src/main.tsx',

recipes/src/step.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class CommandStep extends Step {
4343
const allPrefix = this.ignoreIfBash ? '# ' : '';
4444
for (const command of this.commands) {
4545
let prefix = allPrefix;
46-
if (command === 'npm run serve' || command === 'npm run dev') {
46+
if (command === 'npm run serve' || command === 'npm run dev' || command === 'npm run start') {
4747
prefix = '# ' + prefix;
4848
}
4949
fs.writeSync(fd, prefix + command + '\n');

0 commit comments

Comments
 (0)