Skip to content

Commit

Permalink
make import resolution timeout configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
gwleuverink committed Jan 18, 2024
1 parent 96e545d commit 2881bf3
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 6 deletions.
12 changes: 12 additions & 0 deletions config/bundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@
*/
'caching_enabled' => env('BUNDLE_CACHING_ENABLED', app()->isProduction()),

/*
|--------------------------------------------------------------------------
| Import resolution timeout
|--------------------------------------------------------------------------
|
| The _import() function uses a built-in non blocking polling
| mechanism in order to account for async & deferred script
| loading. Here you can tweak it's internal timout in ms.
|
*/
'import_resolution_timeout' => env('BUNDLE_IMPORT_RESOLUTION_TIMOUT', 500),

/*
|--------------------------------------------------------------------------
| Cache-Control headers
Expand Down
32 changes: 32 additions & 0 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,36 @@ export function bar() {
</script>
```

## Using `_import()` in a script tag without `type="module"`

All previous examples have used the `_import()` function within a script tag with `type='module'`. This instructs the browser to treat the containing code as a module. Practically this means that code gets it's own namespace & you can't reach for variables outside the scope of the script tag.

A script tag with `type="module"` makes your script `defer` by default, so they are loaded in parallel & executed in order. Because of this the `_import()` function has your requested module available immediately. (Since they are loaded in the same order they appeared in the DOM)

This is not the case however when you use a script tag without `type="module"`. A import might still be loading while the page encounters the `_invoke()` function.

Bundle takes care of this problem by checking the internal import map by use of a non-blocking polling mechanism. So you can safely use `_import()` anywhere you want.

Since Bundle's core is included with the first `<x-import />` that you load you do have to either wrap the import inside a `DOMContentLoaded` listener or make the import inline.

```html
<x-import module="lodash/filter" as="filter" />

<script>
document.addEventListener("DOMContentLoaded", async () => {
let filter = await _import("filter");
});
</script>
```

{: .note }

> We like to explore ways to inject Bundle's core on every page. This way the `_import()` function does not have to be wrapped in a `DOMContentLoaded` listener. Check out our [roadmap](https://laravel-bundle.dev/roadmap.html#roadmap) to see what else we're cooking up.
## Minification

<!-- TODO -->

## Sourcemaps

Sourcemaps are disabled by default. You may enable this by setting `BUNDLE_SOURCEMAPS_ENABLED` to true in your env file or by publishing and updating the bundle config.
Expand All @@ -62,6 +92,8 @@ Sourcemaps will be generated in a separate file so this won't affect performance

> If your project stored previously bundled files you need to run the [bundle:clear](https://laravel-bundle.dev/advanced-usage.html#artisan-bundleclear) command
## `_import` resolution timeout

## Cache-Control headers

You're free to tweak Cache-Control headers bundles are served with by publishing the config file and updating the `cache_control_headers` value.
Expand Down
2 changes: 1 addition & 1 deletion src/BundleManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function bundle(string $script): SplFileInfo
$file = "{$this->hash($script)}.min.js";

// Return cached file if available
if (config('bundle.caching_enabled') && $cached = $this->fromDisk($file)) {
if ($this->config()->get('caching_enabled') && $cached = $this->fromDisk($file)) {
return $cached;
}

Expand Down
14 changes: 9 additions & 5 deletions src/Components/Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@

class Import extends Component
{
public BundleManager $manager;

public function __construct(
public string $module,
public ?string $as = null,
public bool $inline = false
) {
$this->manager = BundleManager::new();
}

public function render()
Expand Down Expand Up @@ -45,12 +48,14 @@ protected function bundle()

// Render script tag with bundled code
return view('x-import::script', [
'bundle' => BundleManager::new()->bundle($js),
'bundle' => $this->manager->bundle($js),
]);
}

protected function core(): string
{
$timeout = $this->manager->config()->get('import_resolution_timeout');

return <<< JS
// First make sure window.x_import_modules exists
if(!window.x_import_modules) window.x_import_modules = {}
Expand All @@ -68,8 +73,7 @@ protected function core(): string
// Wait for module to become available (Needed for Alpine support)
const module = await poll(
() => window.x_import_modules[alias],
1000,
5
{$timeout}, 5
)
if(module === undefined) {
Expand All @@ -86,7 +90,7 @@ protected function core(): string
// Import polling helper
async function poll(success, maxDuration, interval) {
async function poll(success, timeout, interval) {
const startTime = new Date().getTime();
while (true) {
Expand All @@ -96,7 +100,7 @@ protected function core(): string
// Check if maxDuration has elapsed
const elapsedTime = new Date().getTime() - startTime;
if (elapsedTime >= maxDuration) {
if (elapsedTime >= timeout) {
console.info(`Unable to resolve '\${alias}'. Operation timed out.`)
throw `BUNDLE TIMEOUT: '\${alias}' could not be resolved`;
}
Expand Down

0 comments on commit 2881bf3

Please sign in to comment.