What are the "Query Suffixes" referred to in the Vite Docs? - javascript

I have been reading through the Vite documentation for Web workers, and it mentioned importing a file using "Query Suffixes," which I have never encountered and am not sure what to search for to learn more. I'm not sure if this is native to Node.js, Vite.js, or if it is a plugin that is built into Vite.
This is the specific section that I am referring to:
Import with Query Suffixes
A web worker script can be directly imported by appending ?worker or ?sharedworker to the import request. The default export will be a custom worker constructor:
import MyWorker from './worker?worker'
const worker = new MyWorker()
The worker script can also use import statements instead of importScripts() - note during dev this relies on browser native support and currently only works in Chrome, but for the production build it is compiled away.
By default, the worker script will be emitted as a separate chunk in the production build. If you wish to inline the worker as base64 strings, add the inline query:
import MyWorker from './worker?worker&inline'
If you wish to retrieve the worker as a URL, add the url query:
import MyWorker from './worker?worker&url'
See Worker Options for details on configuring the bundling of all workers.
Update:
I found an MDN page on import that seems like a step in the direction that I am looking for, as well as this MDN page on import.meta that looks a lot like what I am searching for. I tried following that lead, but it didn't help me understand this Vite feature any better.
Is the ?worker query suffix a custom Vite implementation of import.meta?

Related

GatsbyJS: Import npm package in serviceworker file (gatsby-plugin-offline)

We use gatsby-plugin-offline in order to get a auto-generated service worker. It works fine since all pages are available offline now. With the following code in gatsby-config.js, some additional code can be added to the service worker.
{
resolve: `gatsby-plugin-offline`,
options: {
appendScript: 'src/custom-sw-code.js',
},
},
Within custom-sw-code.js we could not manage to import any npm package so far. If we use import or require on top of the file, browsers complain about non-working serviceworker code (after building and serving the app).
Do you know, how to import packages in the serviceworker?
If you want to pull in external scripts into a service worker, importScripts() will help. (Another option is to use static ES module imports, but they aren't supported in all browsers as of this writing.)
For each script URL you pass in, importScripts() will synchronously download and execute the code within the context of the current ServiceWorkerGlobalScope. The service worker will also take care of automatically caching the scripts, so you don't need to manually add those URLs to a cache, and the request for those scripts won't trigger your service worker's fetch event listeners.
If you're loading code from npm from a CDN, make sure that you're requesting either a UMD or IIFE bundle, and make note of what the exported global symbols are, as that's what will end up being exposed in the ServiceWorkerGlobalScope.

Error registering service-worker script with production build

I'm using Workbox Webpack plugin (v4.3.1) to generate a service worker script and Workbox-Window (v4.3.1) plugin to register it.
It all works fine on dev environment (I use webpack dev server) but with the production build I'm getting the error below on the Chrome (v78) dev console:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker for scope ('http://localhost:4321/') with script ('http://localhost:4321/undefined'): A bad HTTP response code (404) was received when fetching the script.
(Note: Im using a local Nginx server to test my production build)
Im using Workbox Webpack GenerateSW like this:
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: false
})
And I confirmed that, after the build, the service worker script (service-worker.js) is generated and its in the dist folder.
I am using Workbox-Window plugin to register the aforementioned service worker script:
import { Workbox } from 'workbox-window'
if ('serviceWorker' in navigator) {
const wb = new Workbox('/service-worker.js') // Note: I also tried without the bar and with path './service-worker.js' and didnt work
wb.register()
}
I'm guessing the problem is not related to the fact Im using Nginx to test the prod build, nor related with the url or path of the service worker script, provided to the Workbox constructor because, using ServiceWorker Web API instead of Workbox Window API, it works fine:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js') // THIS WORKS!!!
}
Why, under the exact same conditions, the service worker registration fails with Workbox Window API? Where does that undefined, that you can see in the error logs, come from???
* Edit * I opened an issue on Workbox GitHub repo. You can find it here.
I was experiencing this same issue and had my hopes up when I saw your post here. After a mild disappointment I started searching and scavenging the web for some enlightenment. Anyway, I have a setup similar to yours, where on development environments it works but on production it doesn't.
My specific setup is: Python 3 + Flask + Webpack + npm + Apache HTTPD
What I did to solve this issue was to modify the import sentence from:
import { Workbox } from 'workbox-window'
To this:
import { Workbox } from 'workbox-window/Workbox.mjs';
According to this documentation on Google's Workbox website:
Workbox Advanced bundling concepts
Afterwards I was required to update my Webpack setup to bundle Babel-Polyfill so that I was able to avoid the regeneratorRuntime Errors caused by the promises and awaits functions that workbox-window uses, by installing it and including it as stated here: #babel/Polyfill or babel-polyfill depending on your setup and adding it as an entry on the module.exports config.
Hope this helps any one else who suffers this ambiguous and exhausting error.

JS - creating new worker causes 404

I'm using Worker API to create new worker, it's as simple as:
var myWorker = new Worker('src/worker.js');
Unfortunately I'm using webpack to build my project and linking to src/worker.js returns 404.
How can I use it to create my Worker?
import hardWorker from './src/hardWorker.js';
var myWorker = new Worker(HOW TO PUT HARDWORKER HERE?);
Try using the worker-loader plugin for webpack, which can be found here: https://github.com/webpack-contrib/worker-loader
This registers scripts loaded through it as a Web worker, and bundles all of your workers in the main bundle that webpack creates. Using it in your app is as simple as this:
import MyWorker from 'worker-loader!./Worker.js';
const worker = new MyWorker();
Or you can add loader configuration parameters to your webpack.config so all files matching a specific pattern are loaded and registered as workers. The worker-loader has an example of this.
The issue is that the worker API expects a URL to load the work script from and webpack tries to bundle everything into a single file, meaning the src/worker.js file isn't where it needs to be when the browser tries to load it.
There are a couple options.
You could manually copy the worker.js file to wherever the build is trying to load the file from.
You could set up webpack to copy the file to the right location using the CopyWebpackPlugin.
Depending on how complicated your worker is, you could just put the code in a string and create an object URL so the browser doesn't have to load anything from the server at all. This is an approach I've used in the past and have written a helper library for to Workers a little easier to use.
Hope that helps!

How to asynchronously import components in VueJS by full URL

I need to import a Vue component asynchronously by the full URL opposed to relative URL. The following example taken from the VueJS documentation works just fine for components within the same project
Vue.component(
'app-component-one',
() => import('./component-from-app-one')
)
However, my goal is to import components from a separate project that's deployed on the same server. I was hoping I could use the full URL and do something like...
Vue.component(
'app-component-two',
() => import ('http://sample-domain.com/project-2/components/component-from-app-two.vue')
)
but it results in and error:
This dependency was not found:
* http://sample-domain.com/app-2/components/component-from-app-two.vue in ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!./src/components/SampleComponent.vue
Is importing components by full URL possible? Thanks in advance!
The example you referenced from the Vue website is leveraging the code-splitting functionality from WebPack, so it will NOT work to load files that are not part of the same project.
What you are trying to do is typically called "dynamic/asynchronous ES6 module loading". Not to get too deep in to it.. but the current import blah from X only support static imports. If you care more about the nitty-gritty details of this.. there is a TC39 proposal for dynamic imports in JS
In the mean time... us mortals have to depend on tools like SystemJS which will do exactly what you are asking for.
But like #divine mentioned... you need some type of build-process that generates the stand-alone Vue component. You can use either WebPack or RollUp to export it as a UMD and the use SystemJS to import that component by referencing the full URL (you could even import it from a different domain! assuming that domain supports CORS)

Attempting to load a JavaScript sdk into an Angular2 application. Can't find all dependencies

I'm attempting to make use of this library: https://github.com/MagicTheGathering/mtg-sdk-javascript in an Angular2 application.
Unfortunately, I've been going in circles trying to load it into my application.
Firstly, on the TypeScript side if I import it using:
import { } from 'mtgsdk';
there are no types to load into the {}.
If I attempt to load it using something similar to:
import * as mtg from 'mtgsdk'
I'm unable to because it says that it's unable to find a module named mtgsdk.
I've installed the module using
npm install --save mtgsdk
Also, npm installs work fine for other modules.
The application compiles fine if I load it in using require via something similar to this:
var mtg = require('mtgsdk');
Taking that approach, I'm able to compile and launch but in the browser I get a number of errors about modules that it can't find. I figure they are prerequisites for the sdk that didn't get loaded so I start bringing them in via package.json.
For every one that I bring in, I then have to go to systemjs.config.js and add an entry pointing to the module's entry point and often have to specify a default extension using blocks like this:
pointer
'mtgsdk': 'npm:mtgsdk/lib/index.js',
'request-promise': 'npm:request-promise/lib/rp.js',
'ramda': 'npm:ramda/dist/ramda.js',
'emitter20': 'npm:emitter20/index.js',
'bluebird': 'npm:bluebird/js/browser/bluebird.js',
'request': 'npm:request/index.js'
default extension
'request-promise':
{
defaultExtension: 'js'
}
I'm not sure if that's the right approach though because the more dependencies I add, the more that I end up requiring. At one point I had literally gotten up to 50 extra dependencies added because every time I launched, the browser console would find more that were needed.
Is there any easier way to load all of these in?
Also, some of them (such as tough-cookie and request-promise-core) were very problematic to load and I couldn't get the browser console to stop complaining about them. Finally, some of them seemed very basic such as url, http, https. Those seem like they should already be present.
Using systemjs was utilized in the previous versions of Angular 2, However Angular 2 has evolved to Angular 4, with super new features like Angular CLI.
I recommend your use Angular CLI, with #angular/cli.
Importing Node modules
Since mtgsdk is a node-module, you can easily import it using
import * as mtg from 'mtgsdk'
However for your program to compile, you must install a type definition for it. or declare one for it in /typings.json or your app might not build.
Importing Client Scripts
For client scripts like firebase.js you won't need to add client scripts as entries in systemjs.config.js again.
Using #angular/cli, you would easily add them in the scripts[] array in your angular-cli.json for automatic compilation.
Then access them like this
declare const firebase: any;
Here is a quickstart tutorial to set up Angular with #angular/cli.

Categories

Resources