Skip to content

Commit c8fd074

Browse files
arbrandesclaude
andcommitted
feat: compile runtime/shell to JS before publishing
Ship compiled JavaScript + .d.ts declarations instead of raw TypeScript source. This allows consuming apps to also pre-compile their TypeScript and use tsc-alias to resolve arbitrary paths (such as @src). And so that `npm run dev` can also resolve these paths, we add tsconfig-paths-webpack-plugin to webpack.config.dev. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2badcaf commit c8fd074

13 files changed

Lines changed: 176 additions & 45 deletions

.npmignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
__mocks__
21
node_modules
3-
*.test.js
4-
*.test.jsx
5-
*.test.ts
6-
*.test.tsx

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ doc_command = ./node_modules/.bin/documentation build src -g -c ./docs/documenta
1111
cat_docs_command = cat ./docs/_API-header.md ./docs/_API-body.md > ./docs/API.md
1212

1313
build:
14-
rm -rf ./config ./tools/dist
14+
rm -rf ./config ./tools/dist ./dist
1515
tsc --project ./tsconfig.json
16+
tsc --project ./tsconfig.build.json
17+
mkdir -p ./dist/shell
18+
cp ./shell/app.scss ./dist/shell/app.scss
1619
mkdir -p ./config
1720
cp tools/typescript/tsconfig.json config/tsconfig.json
1821
tsc --project ./tools/tsconfig.json

docs/decisions/0008-stylesheet-import-in-site-config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ As a best practice, a project should have a top-level SCSS file as a peer to the
2121
The `site.scss` file should import the stylesheet from the shell:
2222

2323
```diff
24-
+ @import '@openedx/frontend-base/shell/app.scss';
24+
+ @import '@openedx/frontend-base/dist/shell/app.scss';
2525

2626
// other styles
2727
```

docs/how_tos/migrate-frontend-app.md

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ With the exception of any custom scripts, replace the `scripts` section of your
128128

129129
```json
130130
"scripts": {
131+
"build": "tsc --project tsconfig.build.json && tsc-alias -p tsconfig.build.json",
131132
"dev": "PORT=YOUR_PORT PUBLIC_PATH=/YOUR_APP_NAME openedx dev",
132133
"i18n_extract": "openedx formatjs extract",
133134
"lint": "openedx lint .",
@@ -137,6 +138,12 @@ With the exception of any custom scripts, replace the `scripts` section of your
137138
},
138139
```
139140

141+
The `build` script compiles TypeScript to JavaScript and uses `tsc-alias` to rewrite `@src` path aliases to relative paths. You'll need to install `tsc-alias` as a dev dependency:
142+
143+
```sh
144+
npm install --save-dev tsc-alias
145+
```
146+
140147
- Replace `YOUR_PORT` with the desired port, of course.
141148
- Replace `YOUR_APP_NAME` with the basename used on your site.config, not doing this will result in only the root route working.
142149
- Note that `fedx-scripts` no longer exists, and has been replaced with `openedx`.
@@ -150,21 +157,24 @@ Other package.json edits
150157

151158
- Change the author to "Open edX"
152159

153-
main
154-
----
160+
main and types
161+
--------------
162+
163+
Point to the compiled output:
155164

156165
```json
157-
"main": "src/index.ts",
166+
"main": "dist/index.js",
167+
"types": "dist/index.d.ts",
158168
```
159169

160170
files
161171
-----
162172

163-
This is a buildless library, so we package files in `src`:
173+
Package the compiled output in `dist`:
164174

165175
```json
166176
"files": [
167-
"/src"
177+
"/dist"
168178
],
169179
```
170180

@@ -196,15 +206,10 @@ Finally, make sure the following fields are set properly:
196206
Clean up .npmignore
197207
===================
198208

199-
This is what should be in the repo's `.npmignore`. No more, no less:
209+
Since we use the `files` field in `package.json` to whitelist only `/dist`, the `.npmignore` file is largely unnecessary. You can delete it or keep a minimal version:
200210

201211
```
202-
__mocks__
203212
node_modules
204-
*.test.js
205-
*.test.jsx
206-
*.test.ts
207-
*.test.tsx
208213
```
209214

210215
Clean up .gitignore
@@ -259,8 +264,12 @@ Create a `tsconfig.json` file and add the following contents to it:
259264
{
260265
"extends": "@openedx/frontend-base/config/tsconfig.json",
261266
"compilerOptions": {
267+
"baseUrl": ".",
262268
"rootDir": ".",
263269
"outDir": "dist",
270+
"paths": {
271+
"@src/*": ["./src/*"]
272+
}
264273
},
265274
"include": [
266275
"src/**/*",
@@ -275,6 +284,57 @@ Create a `tsconfig.json` file and add the following contents to it:
275284

276285
This assumes you have a `src` folder and your build goes in `dist`, which is the best practice.
277286

287+
The `@src` path alias
288+
---------------------
289+
290+
The `paths` configuration above sets up the `@src` alias, which allows you to import from your app's `src` directory using `@src/...` instead of relative paths. For example:
291+
292+
```typescript
293+
// Instead of:
294+
import { MyComponent } from '../../../components/MyComponent';
295+
296+
// You can use:
297+
import { MyComponent } from '@src/components/MyComponent';
298+
```
299+
300+
For this to work, the app must define its own `@src` path mapping in `tsconfig.json`. **tsc-alias** will then rewrite `@src` imports to relative paths during the build step, so the compiled JavaScript has proper paths.
301+
302+
Add a tsconfig.build.json file
303+
------------------------------
304+
305+
Create a `tsconfig.build.json` file for compiling your app before publishing:
306+
307+
```json
308+
{
309+
"extends": "./tsconfig.json",
310+
"compilerOptions": {
311+
"rootDir": "src",
312+
"outDir": "dist",
313+
"noEmit": false,
314+
"declaration": true,
315+
"declarationMap": false,
316+
"sourceMap": false
317+
},
318+
"include": [
319+
"src/**/*"
320+
],
321+
"exclude": [
322+
"src/**/*.test.ts",
323+
"src/**/*.test.tsx",
324+
"src/**/*.spec.ts",
325+
"src/**/*.spec.tsx",
326+
"src/__mocks__/**/*",
327+
"src/setupTest.js"
328+
]
329+
}
330+
```
331+
332+
This config:
333+
- Extends your main `tsconfig.json`
334+
- Outputs compiled JavaScript and type declarations to `dist/`
335+
- Excludes test files and mocks from the published package
336+
- Disables source maps for smaller package size
337+
278338

279339
Edit jest.config.js
280340
===================
@@ -789,7 +849,7 @@ Create a new `app.scss` file at the top of your application. It's responsible f
789849
For example:
790850

791851
```
792-
@use "@openedx/frontend-base/shell/app.scss";
852+
@use "@openedx/frontend-base/dist/shell/app.scss";
793853
@use "sass/style";
794854
```
795855

@@ -876,17 +936,18 @@ First, rename `src/plugin-slots`, if it exists, to `src/slots`. Modify imports
876936
Next, the frontend-base equivalent to `<PluginSlot />` is `<Slot />`, and has a different API. This includes a change in the slot ID, according to the [new slot naming ADR](../decisions/0009-slot-naming-and-lifecycle.rst) in this repository. Rename them accordingly. You can refer to the `src/shell/dev` in this repository for examples.
877937

878938

879-
Remove build step from CI
880-
=========================
939+
Update build step in CI
940+
=======================
881941

882-
In `.github/workflow/ci.yml`, remove the build step.
942+
In `.github/workflow/ci.yml`, ensure the build step runs the TypeScript compilation:
883943

884-
```diff
944+
```yaml
885945
- name: Test
886946
run: npm run test
887-
- - name: Build
888-
- run: npm run build
947+
- name: Build
948+
run: npm run build
889949
- name: i18n_extract
890950
run: npm run i18n_extract
891951
```
892-
```
952+
953+
The build step compiles TypeScript to JavaScript and rewrites `@src` path aliases using `tsc-alias`.

package-lock.json

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
"publishConfig": {
66
"access": "public"
77
},
8-
"main": "index.ts",
8+
"main": "dist/index.js",
9+
"types": "dist/index.d.ts",
910
"files": [
1011
"/config",
11-
"/runtime",
12-
"/tools/dist",
13-
"/shell",
14-
"/types.ts"
12+
"/dist",
13+
"/tools/dist"
1514
],
1615
"bin": {
1716
"intl-imports.js": "tools/dist/cli/intl-imports.js",
@@ -118,6 +117,7 @@
118117
"source-map-loader": "4.0.2",
119118
"style-loader": "^4.0.0",
120119
"ts-loader": "^9.5.1",
120+
"tsconfig-paths-webpack-plugin": "^4.2.0",
121121
"typescript": "^5.6.3",
122122
"typescript-eslint": "^8.11.0",
123123
"universal-cookie": "^8.0.1",

test-site/tsconfig.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
{
22
"extends": "@openedx/frontend-base/config/tsconfig.json",
33
"compilerOptions": {
4+
"baseUrl": ".",
45
"rootDir": ".",
5-
"outDir": "dist"
6+
"outDir": "dist",
7+
"paths": {
8+
"@src/*": ["./src/*"]
9+
}
610
},
711
"include": [
812
"eslint.config.js",

tools/tsconfig.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
"outDir": "dist",
66
"noEmit": false,
77
"allowJs": true,
8-
"resolveJsonModule": true,
9-
"paths": {
10-
"@src/*": ["./src/*"]
11-
}
8+
"resolveJsonModule": true
129
},
1310
"include": [
1411
"babel/**/*",

tools/webpack/webpack.config.build.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const config: Configuration = {
2424
mode: 'production',
2525
devtool: 'source-map',
2626
entry: {
27-
app: path.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/shell/site'),
27+
app: path.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/dist/shell/site'),
2828
},
2929
output: {
3030
filename: '[name].[chunkhash].js',
@@ -36,7 +36,6 @@ const config: Configuration = {
3636
alias: {
3737
...aliases,
3838
'site.config': resolvedSiteConfigPath,
39-
'@src': path.resolve(process.cwd(), 'src'),
4039
},
4140
extensions: ['.js', '.jsx', '.ts', '.tsx'],
4241
},

tools/webpack/webpack.config.dev.shell.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ const config: Configuration = {
3434
alias: {
3535
...aliases,
3636
'site.config': resolvedSiteConfigPath,
37-
'@src': path.resolve(process.cwd(), 'src'),
3837
},
3938
extensions: ['.js', '.jsx', '.ts', '.tsx'],
4039
},

0 commit comments

Comments
 (0)