Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@code-dot-org/ml-playground",
"version": "0.0.48",
"version": "0.0.49",
"private": false,
"repository": {
"type": "git",
Expand Down
23 changes: 19 additions & 4 deletions src/assetPath.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
(
global as unknown as Record<string, unknown>
).__ml_playground_asset_public_path__ = './assets/';

// Consumer-facing setter for the ml-playground asset base path.
//
// The function writes a single property on the shared page global,
// which the main bundle reads at startup (see `setPublicPath.ts`) to
// assign webpack's `__webpack_public_path__`. That assignment is what
// controls image and chunk URLs at runtime.
//
// Ordering: call this BEFORE the ml-playground main bundle is loaded
// (i.e. before `require('@code-dot-org/ml-playground')` or any import
// that resolves through the main entry). Asset URLs are computed when
// each asset module first evaluates, so a late call can't retroactively
// rewrite them. The natural CommonJS pattern (`setAssetPath(...); const
// ml = require('@code-dot-org/ml-playground'); ...`) is correct;
// pure-ESM consumers should call this then `await import(...)` the
// main entry.
//
// No module-init side effect on purpose — the fallback for "consumer
// never set it" lives in `setPublicPath.ts` as `|| './'`, so there's
// one place to look when chasing publicPath behavior.
export const setAssetPath = (path: string): void => {
(
global as unknown as Record<string, unknown>
Expand Down
1 change: 1 addition & 0 deletions src/indexDev.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './assetPath';
import './setPublicPath';
import {initAll, instructionsDismissed} from './index';
import queryString from 'query-string';
import {ModelDataToSave, SaveResponse} from './types';
Expand Down
1 change: 1 addition & 0 deletions src/indexProd.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import './setPublicPath';
export {initAll, instructionsDismissed} from './index';
33 changes: 33 additions & 0 deletions src/setPublicPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Wire the runtime asset-path global into webpack's publicPath.
//
// Image imports (e.g. `import bot from './ai-bot-body.png'`) and any
// other webpack `asset` / `asset/resource` modules resolve their URLs
// against webpack's runtime `publicPath`. The default is `'auto'`,
// which infers the path from where the host page loaded the script —
// not what we want when the package is embedded into a consumer like
// apps's dashboard, which serves these images from a different base
// path (e.g. `/blockly/media/skins/ailab/`).
//
// Webpack exposes `__webpack_public_path__` as a magic variable: any
// assignment to it at runtime updates the publicPath used by
// subsequently-evaluated asset modules. We pull the desired base from
// the same global the dataset/manifest loader already uses
// (`__ml_playground_asset_public_path__`), so the consumer has one
// knob to turn.
//
// This module MUST be imported before any module that pulls in an
// image — i.e. it should be the first import in the entry file.
// ECMAScript guarantees depth-first evaluation order: when an entry
// does `import './setPublicPath'; import './index';`, this module's
// body runs to completion before `./index` starts evaluating, so all
// downstream asset modules see the updated `__webpack_public_path__`.
// `__webpack_public_path__` is a webpack magic variable: at build time
// webpack rewrites assignments to it as updates to its runtime
// `__webpack_require__.p`. ESLint doesn't understand this — it sees a
// `let` with a single assignment and no read, hence the disables.
/* eslint-disable prefer-const, @typescript-eslint/no-unused-vars */
declare let __webpack_public_path__: string;
__webpack_public_path__ =
(global as unknown as Record<string, string>)
.__ml_playground_asset_public_path__ || './';
/* eslint-enable prefer-const, @typescript-eslint/no-unused-vars */
9 changes: 8 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ const commonConfig = {
},
},
generator: {
filename: 'assets/images/[name][ext][query]',
// URLs resolve to `<__webpack_public_path__>images/<name>`
// at runtime. The consumer sets the public path via
// `__ml_playground_asset_public_path__` (see
// `src/setPublicPath.ts`); leaving an `assets/` prefix here
// would double up against consumer paths that already end
// in `assets/` or similar, so the prefix lives entirely on
// the consumer side.
filename: 'images/[name][ext][query]',
},
},
],
Expand Down
Loading