vite-pwa / docs Goto Github PK
View Code? Open in Web Editor NEWDocumentation: PWA integrations for Vite and the ecosystem
Home Page: https://vite-pwa-org.netlify.app/
License: MIT License
Documentation: PWA integrations for Vite and the ecosystem
Home Page: https://vite-pwa-org.netlify.app/
License: MIT License
Hi
when running the SvelteKit guide to setup the plugin, you need to configure outDir to be "static" otherwise adapter static overwrites the sw+manifest generated to build.
And yo need to run the command basically twice, because adapter static apparently does not pick the resulting files anymore.
This how it works (almost) - generating to static so I can pick it up for build -
.....
.svelte-kit/output/client/_app/immutable/chunks/index-1c8a281e.js 9.50 kB │ gzip: 4.02 kB
.svelte-kit/output/client/_app/immutable/start-d8fce51b.js 29.19 kB │ gzip: 10.69 kB
.svelte-kit/output/client/_app/immutable/chunks/index4-df3e774f.js 32.59 kB │ gzip: 12.66 kB
.svelte-kit/output/client/_app/immutable/components/pages/_page.svelte-25a1c2d4.js 35.21 kB │ gzip: 10.39 kB
.svelte-kit/output/client/_app/immutable/chunks/swiper.bundle-2b70fa67.js 95.69 kB │ gzip: 25.84 kB
.svelte-kit/output/client/_app/immutable/chunks/_layout-f42120d7.js 934.64 kB │ gzip: 168.55 kB
(!) Some chunks are larger than 500 kBs after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
PWA v0.14.1
mode generateSW
precache 79 entries (3353.50 KiB)
files generated
static\sw.js
static\workbox-7369c0e1.js
> Using @sveltejs/adapter-static
Wrote site to "build"
✔ done
C:\Data\src\rommelzolder\ionic-sveltekit-ssr-demo>
const pwaConfiguration = {
outDir: './static',
includeAssets: ['favicon.svg', 'favicon.ico', 'robots.txt', 'apple-touch-icon.png', 'dist/*'],
base: '/',
scope: '/',
manifest: pwaManifest
}
content of build: no sw.js and workbox-.js nor manifest.
content of static: has sw.js and workbox-.js
Example repo - https://github.com/Tommertom/ionic-sveltekit-ssr-demo
Please note, this repo already has a manifest file in static (empty) for other reasons.
Hi
Below instruction fails while wanting to install Vite PWA for SvelteKit on https://vite-pwa-org.netlify.app/frameworks/sveltekit.html
PROMTP> pnpm add -D @vite-pwa/sveltekit
ERR_PNPM_FETCH_404 GET https://registry.npmjs.org/@vite-pwa%2Fsveltekit: Not Found - 404
This error happened while installing a direct dependency of C:\Data\src\crap\kitrcionictest
@vite-pwa/sveltekit is not in the npm registry, or you have no permission to fetch it.
No authorization header was set for the request.
Progress: resolved 17, reused 17, downloaded 0, added 0
Install via npm also does not work npm i -D @vite-pwa/sveltekit
. Same error.
Hi,
The docs mention that You must add a robots.txt file to allow search engines to crawl all your application pages.
Why is that?
A robots.txt file allowing everything seems to be unnecessary:
Do I have to include an allow rule to allow crawling?
No, you do not need to include an allow rule. All URLs are implicitly allowed and the allow rule is used to override disallow rules in the same robots.txt file.
Also:
Thank you!
When running node '.\node_modules\@vite-pwa\assets-generator\bin\pwa-assets-generator.mjs' --preset minimal-2023 .\public\door.svg
I get in the output the "Html Head Links" and the "PWA web manifest icons entry" code (HTML and JSON).
I manually added the header links to my index.html
but I do not know where to put the "icons"
JSON so that it is ultimately added to dist/manifest.webmanifest
.
After building my app and manually adding the "icons"
attribute to the generated dist/manifest.webmanifest
file the PWA works fine. dist/manifest.webmanifest
is however recreated at each build, erasing my "icons"
entry.
How can I have the two merged at build time? (specifically: merging the dist/manifest.webmanifest
generated during build with the JSON code I see on the output that I would copy in some file)
I am trying to setup minimal setup vite&react app with configuration registerType: 'autoUpdate'
.
VitePWA({ registerType: 'autoUpdate' })
I have tried other configuration options for workbox likeskipWaiting: true, clientsClaim: true
but throw same error on page open. This probably leads hitting empty page after deploy unless clear cache or new tab open.
Thanks for help.
As I am trying to upgrade from 0.31 to 0.32, I am getting the following error in my tests. I presume it's because Vitest now throws an error when a module cannot be resolved. I am not really sure how to resolve this, I presume it's because of how this gets imported, aka route being virtual `from 'virtual:pwa-register/vue';
I've developed a favicon generator site (https://favicon.inbrowser.app/) with the following features:
"purpose": "any"
and "purpose": "maskable"
support.I hope you can add my tool to the following document to assist more people in generating favicon assets with ease.
docs/guide/pwa-minimal-requirements.md
Lines 90 to 92 in ea5a0f4
How to set ignoreVary for matching cache in ?
Cannot seem to get runtime caching to allow for caching of api data.
vite.config.js
import { defineConfig } from "vite";
import Components from "unplugin-vue-components/vite";
import vue from "@vitejs/plugin-vue2";
import { VitePWA } from "vite-plugin-pwa";
//Runtime Caching
export default defineConfig({
alias: {
"@": require("path").resolve(__dirname, "src"),
},
plugins: [
vue(),
Components(),
VitePWA({
//Runtime
workbox: {
runtimeCaching: [
{
urlPattern: "https://www.themealdb.com/*", // Adjust the URL pattern to match your API endpoint
handler: "NetworkFirst",
options: {
cacheName: "mealDb", // Name for your cache
expiration: {
maxEntries: 500,
maxAgeSeconds: 60 * 60 * 24,
purgeOnQuotaError: true,
},
cacheableResponse: { statuses: [0, 200] },
},
},
],
},
strategies: "injectManifest",
srcDir: "src",
filename: "sw.js",
injectManifest: {
globPatterns: [
// all packaged resources are stored here
"assets/*",
// add HTML and other resources for the root directory
"*.{svg,png,jpg}",
"*.html",
//"manifest.webmanifest",
// be careful, not to add sw.js
],
},
manifest: {
name: "Test Project",
short_name: "Test",
theme_color: "#ffffff",
id: "/",
description: "Vue PWA ",
display: "standalone",
background_color: "#ffffff",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
purpose: "any maskable",
},
],
},
}),
],
});
sw.js
import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching";
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") self.skipWaiting();
});
cleanupOutdatedCaches();
precacheAndRoute(self.__WB_MANIFEST);
Your proposed solution
@R0N1n-dev workbox-build only works in one mode, if you are using custom sw (injectManifest strategy), you MUST include runtimeCaching in your service worker logic, check this for example: https://github.com/elk-zone/elk/blob/main/service-worker/sw.ts#L56-L94
Those entries are the equivalent to your workbox.runtimeCaching handler: when using generateSW strategy, workbox-build will generate a registerRoute per plugin in the sw output.
In summary, when using generateSW workbox-build will be configured using workbox pwa plugin configuration entry; when using injectManifest strategy workbox-build will be configured using injectManifest pwa plugin configuration entry.
I really wish you guys wouldn't close the issue b4 confirmation that ur proposed solution is working, because it is not and now i will reopen it till i get a working solution
Docs state:
You can also configure how to control the network requests interception for any of your application resources. You can find more information on Workbox - Caching Strategies. -- https://vite-pwa-org.netlify.app/guide/service-worker-precache.html
The linked workbox doc talks about cache-only, network-only, and cache-first-then-network, network-first-then-cache, showing you how to implement this if your implementing the caching yourself (and hence the entire service worker yourself). That's not really helpful - I'm using vite-pwa to avoid having to write the SW and caching implementation myself! Neither docs hint at a workbox or vite-pwa option to configure any one of the strategies.
AFAICT vite-pwa just generates a service worker with a cache-only strategy and there is no option to select a strategy. Is that the case? If so, saying "You can also configure how to control the network requests interception for any of your application resources" seems misleading/erroneous, and "configure" should be "implement you own".
I think I found a typo on https://vite-pwa-org.netlify.app/guide/static-assets.html, second paragraph.
You can also add another static assets such as...
=> You can also add other static assets such as...
Please excuse me for being a bit lazy and not wanting to go through the whole forking and checking out and PR-ing, just for two letters, so I'm hoping this report is sufficient for someone who already has everything ready to fix this possible typo.
Btw, if there are other facilities for reporting typos like these, you might want to add those to the Contributing Guidelines too.
Add headers object on fetch init method: https://vite-pwa-org.netlify.app/guide/periodic-sw-updates.html#handling-edge-cases
For example, when installing in path/a, I can know that the/a path is recorded, and next time I open it, I will open this directory by default
And how can I set the cache to support POST regular expressions?
hi userquin what is a better way for use case:
I have, an nginx proxy for aws up/
after the prefix, for example, https://site.com/up/bucket-folder/dir/image.jpg
,
how to cache dynamic images for /up/*.jpg
or any file ext:
runtimeCaching: [
{
urlPattern: /\/up\/.*\/*/,
handler: 'CacheFirst',
options: {
cacheName: 'images-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
is the right solution?
I get 404 page, but it works after hard-reload in vite preview mode, don't understand why :(
It is possible to clean local storage when immediate is set to true?
Hello!
I'm sorry this is such a simple question.
https://vite-pwa-org.netlify.app/frameworks/vue.html mentions a module type declaration and provides the contents for virtual:pwa-register/vue
. What exactly if this file to be named and where is it supposed to live?
It would be awesome if this was also clarified in the docs.
Thanks in advance!
I've configured my vite to use another dist folder:
build: {
target: 'esnext',
outDir: '../dist',
emptyOutDir: true,
},
I notice that when building vite with VitePWA dev mode enabled, it creates anopther folder called 'dev-dist' that contains the registerSW.js, sw.js and workbox-*.js files.
Is there a way to configure where these files are put? I just want them to go into the vite configured dist folder.
Is there any documentation about using this plugin to send native mobile notifications?
Greetings,
I understand what vite-pwa
is made to support full fledged PWAs, however I don't want PWA support(caching), but only to install SW for fetch
interception, in order to make transparent refresh for auth token.
Can you add such simple support to vite-pwa
, or guide how to do it manually.
My project structure is:
src/
src/service-worker.js
I do in my main.tsx
:
// Register the Service Worker
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/service-worker.js")
}
However service-worker
is not copied to dist/
and can't be loaded in development
.
Thank you and best,
Dragomir
When I include '@vite-pwa/nuxt' in modules I get data-ssr="false". The page is never server rendered.
When I exclude it, data-ssr is true again. Why does this happen?
Cannot seem to get runtime caching to allow for caching of api data.
vite.config.js
import { defineConfig } from "vite";
import Components from "unplugin-vue-components/vite";
import vue from "@vitejs/plugin-vue2";
import { VitePWA } from "vite-plugin-pwa";
//Runtime Caching
export default defineConfig({
alias: {
"@": require("path").resolve(__dirname, "src"),
},
plugins: [
vue(),
Components(),
VitePWA({
//Runtime
workbox: {
runtimeCaching: [
{
urlPattern: "https://www.themealdb.com/*", // Adjust the URL pattern to match your API endpoint
handler: "NetworkFirst",
options: {
cacheName: "mealDb", // Name for your cache
expiration: {
maxEntries: 500,
maxAgeSeconds: 60 * 60 * 24,
purgeOnQuotaError: true,
},
cacheableResponse: { statuses: [0, 200] },
},
},
],
},
strategies: "injectManifest",
srcDir: "src",
filename: "sw.js",
injectManifest: {
globPatterns: [
// all packaged resources are stored here
"assets/*",
// add HTML and other resources for the root directory
"*.{svg,png,jpg}",
"*.html",
//"manifest.webmanifest",
// be careful, not to add sw.js
],
},
manifest: {
name: "Test Project",
short_name: "Test",
theme_color: "#ffffff",
id: "/",
description: "Vue PWA ",
display: "standalone",
background_color: "#ffffff",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
purpose: "any maskable",
},
],
},
}),
],
});
sw.js
import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching";
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") self.skipWaiting();
});
cleanupOutdatedCaches();
precacheAndRoute(self.__WB_MANIFEST);
According to the manual:
"When the user clicks the "refresh" button when onNeedRefresh is called, then calls updateSW() function; the page will reload, and the up-to-date content will be served."
Yes, this works, but all the assets are loaded from the network even though the service worker has cached them all. This makes the application feel sluggish after each update. When you first open the app, the service worker immediately goes to work, and all assets are correctly cached. But the caching breaks when updateSW() is called. Is this a bug am I missing out on something?
My JS code is identical to the example given in the documentation.
const updateSW = registerSW({
immediate: true,
// Shows UPDATE button in the top toolbar
onNeedRefresh() {
Bus.$emit('show-reload');
},
onRegisteredSW(swUrl, registered) {
registered && setInterval(async () => {
if (!(!registered.installing && navigator)) return
if (('connection' in navigator) && !navigator.onLine) return
const resp = await fetch(swUrl, {
cache: 'no-store',
headers: {
'cache': 'no-store',
'cache-control': 'no-cache',
},
})
if (resp?.status === 200) {
await registered.update();
}
}, intervalMS)
},
})
// When user click on the update button we will execute updateSW() that
// activate the new SW reloads pre-cache + reloads the page
Bus.$on('update-approved', () => {
updateSW();
});
Wondering if there's anyway to apply conditional styling based on whether or not you're within a PWA. Would be nice to have if not.
Hello, I'm currently trying to configure the Service Worker precache so that I can cache all my files when installing the application but I noticed a strange behavior when trying different approaches using the Vite PWA docs.
If I configure the VitePWA
plugin using the following configuration:
VitePWA({
// Public resources
// includeAssets: [],
// Manifest configuration.
// https://vite-pwa-org.netlify.app/guide/pwa-minimal-requirements.html
manifest: {
...,
icons: [
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any',
},
{
src: 'maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
},
// Workbox configuration.
// workbox: {
// globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
// },
}),
Then, it would result in the following Service Worker precache after build. Please note that public/
files are not being included as part of the precache array (e.g. apple-touch-icon
, favicon.ico
, logo.svg
, robots.txt
etc.), at least not like the Static assets handling page statement.
e.precacheAndRoute(
[
{ url: 'assets/index.0fb3162c.js', revision: null },
{ url: 'assets/index.f0b36889.css', revision: null },
{ url: 'assets/workbox-window.prod.es5.e0cc53cf.js', revision: null },
{ url: 'index.html', revision: 'ecfa72ef5ede33cddcab4b29ddfff4ff' },
{ url: 'pwa-64x64.png', revision: '160c4d06af493fa1cb62ae9f4258003b' },
{
url: 'pwa-192x192.png',
revision: '9397e91d5e3a42bfa03ce2d07f7e3171',
},
{
url: 'pwa-512x512.png',
revision: '49e40aedc6b5cd06157f00d8c564e379',
},
{
url: 'maskable-icon-512x512.png',
revision: 'a51a4f0cc05f269554afef971b7f658d',
},
{
url: 'manifest.webmanifest',
revision: 'f9addcd4a864ed3a97c677e5274540c8',
},
],
{}
),
Moreover, if I configure the VitePWA
plugin using the following configuration instead:
VitePWA({
// Public resources
includeAssets: [
'apple-touch-icon-180x180',
'favicon.ico',
'logo.svg',
'robots.txt',
],
// Manifest configuration.
// https://vite-pwa-org.netlify.app/guide/pwa-minimal-requirements.html
manifest: {
...,
icons: [
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any',
},
{
src: 'maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
},
// Workbox configuration.
// workbox: {
// globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
// },
}),
Then, it would result in the following Service Worker precache after build, which is more accurate to what I'm looking for. However, I'm still missing other valuable assets that were auto-generated by Vite using a hash in their name.
e.precacheAndRoute(
[
{ url: 'assets/index.0fb3162c.js', revision: null },
{ url: 'assets/index.f0b36889.css', revision: null },
{ url: 'assets/workbox-window.prod.es5.e0cc53cf.js', revision: null },
{ url: 'index.html', revision: 'ecfa72ef5ede33cddcab4b29ddfff4ff' },
{ url: 'favicon.ico', revision: '547587c645ecf0155439c8e0edb6cb3d' },
{ url: 'logo.svg', revision: '40dcf9f191738beb353d7a53edb8abd9' },
{ url: 'robots.txt', revision: 'f77c87f977e0fcce05a6df46c885a129' },
{ url: 'pwa-64x64.png', revision: '160c4d06af493fa1cb62ae9f4258003b' },
{
url: 'pwa-192x192.png',
revision: '9397e91d5e3a42bfa03ce2d07f7e3171',
},
{
url: 'pwa-512x512.png',
revision: '49e40aedc6b5cd06157f00d8c564e379',
},
{
url: 'maskable-icon-512x512.png',
revision: 'a51a4f0cc05f269554afef971b7f658d',
},
{
url: 'manifest.webmanifest',
revision: 'f9addcd4a864ed3a97c677e5274540c8',
},
],
{}
),
Furthermore, if I configure the VitePWA
plugin using the following configuration:
VitePWA({
// Public resources
// includeAssets: [],
// Manifest configuration.
// https://vite-pwa-org.netlify.app/guide/pwa-minimal-requirements.html
manifest: {
...,
icons: [
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any',
},
{
src: 'maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
},
// Workbox configuration.
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
},
}),
Then, it would result in the following Service Worker precache after build. Which is exactly what I'm looking for, but then you may notice that there are duplicates in the output from the manifest itself (e.g. pwa-{size}
images).
e.precacheAndRoute(
[
{
url: 'apple-touch-icon-180x180.png',
revision: '9b7a985648e65a01c130fa6e22b2459b',
},
{ url: 'assets/app-logo.007611f1.svg', revision: null },
{ url: 'assets/close.915249f6.svg', revision: null },
{ url: 'assets/image1.47eb2262.png', revision: null },
{ url: 'assets/image2.82abb677.png', revision: null },
{ url: 'assets/image3.0727d240.png', revision: null },
{ url: 'assets/image4.c21696be.png', revision: null },
{ url: 'assets/image5.976b0ba1.png', revision: null },
{ url: 'assets/index.0fb3162c.js', revision: null },
{ url: 'assets/index.f0b36889.css', revision: null },
{ url: 'assets/settings.e67704e2.svg', revision: null },
{ url: 'assets/workbox-window.prod.es5.e0cc53cf.js', revision: null },
{ url: 'favicon.ico', revision: '547587c645ecf0155439c8e0edb6cb3d' },
{ url: 'index.html', revision: 'ecfa72ef5ede33cddcab4b29ddfff4ff' },
{ url: 'logo.svg', revision: '40dcf9f191738beb353d7a53edb8abd9' },
{
url: 'maskable-icon-512x512.png',
revision: 'a51a4f0cc05f269554afef971b7f658d',
},
{
url: 'pwa-192x192.png',
revision: '9397e91d5e3a42bfa03ce2d07f7e3171',
},
{
url: 'pwa-512x512.png',
revision: '49e40aedc6b5cd06157f00d8c564e379',
},
{ url: 'pwa-64x64.png', revision: '160c4d06af493fa1cb62ae9f4258003b' },
{ url: 'pwa-64x64.png', revision: '160c4d06af493fa1cb62ae9f4258003b' },
{
url: 'pwa-192x192.png',
revision: '9397e91d5e3a42bfa03ce2d07f7e3171',
},
{
url: 'pwa-512x512.png',
revision: '49e40aedc6b5cd06157f00d8c564e379',
},
{
url: 'maskable-icon-512x512.png',
revision: 'a51a4f0cc05f269554afef971b7f658d',
},
{
url: 'manifest.webmanifest',
revision: 'f9addcd4a864ed3a97c677e5274540c8',
},
],
{}
),
I don't think having duplicates is such a problem since they have the same revision, but still it's unclear to me what approach should I take considering:
a. It looks like the Static assets handling page is not accurate based on my tests
b. Including assets manually through includeAssets
helps on adding public files into the precache, but it won't help for other files
c. The most accurate approach, which is using globPatterns
is causing duplicate file revisions
Last but not least, I was hoping to develop my own Service Worker using injestManifest
strategy instead of generateSW
, which only requires me to change from workbox.globPatterns
to injectManifest.globaPatterns
. However, I'm facing the exact same issue having duplicate file revisions, so it's not up to the strategy I'm using.
Thanks in advance!
EDIT: I forgot to share the Dev Tools output that shows up all files just once (which is good!), so the issue would remain on the precache generation only, which seems like a minor thing.
Omitted custom images and icons from the screenshot, leaving just manifest files.
when the mode is offline, for Every page I wanted to redirect to offline page (pages/offline.vue)
below is my existing pwa configuration
pwa: {
strategies: 'generateSW',
injectRegister: 'auto',
registerType: 'autoUpdate',
manifest: {
name: "Testing web app BETA",
short_name: "Testing web app BETA",
start_url: "/?pwa",
scope: "/",
icons: [
{
src: "maskable_icon.png",
sizes: "384x384",
type: "image/png",
purpose: "maskable"
},
{
src: "android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
purpose: "any"
},
{
src: "android-chrome-256x256.png",
sizes: "256x256",
type: "image/png"
},
{
src: "icon.png",
sizes: "512x512",
type: "image/png"
}
],
theme_color: "#245BA7",
background_color: "#000000",
display: "standalone"
},
workbox: {
navigateFallback: '/offline',
globPatterns: ['**/*.{js,css,html,png,PNG,svg,jpg,JPG,jpeg}'],
},
devOptions: {
enabled: true,
type: "module",
navigateFallback: '/',
}
}
Can anybody help ?
Greetings,
Firstly, I want to express my gratitude for the outstanding plugin you've developed. It has greatly enhanced my project's functionality.
Issue Overview:
I've encountered a challenge while utilizing the vite-pwa nuxt 3 plugin within my project. In my project's public folder, I have a subdirectory designated for displaying various assets. However, my reverse proxy setup is configured to deny access to all other subdirectories except this designated one.
Upon running the Nuxt build process, the plugin generates the following output structure:
While I've successfully managed to configure the service worker (sw.js
) and the Workbox file (workbox.js
) to be served from the subdirectory by incorporating the following configuration in nuxt.config.js
:
workbox: {
swDest: '/public/subdirectory/sw.js'
}
However, the challenge arises when attempting to automatically generate the manifest.webmanifest
file within the subdirectory during the manifest generation process facilitated by the plugin.
I am unable to locate any configuration options within the plugin's documentation that would allow me to specify the output directory for the manifest file.
Any sort of guidance or assistance in resolving this issue would be really helpful.
hi, I'm using "@vite-pwa/nuxt": "^0.0.4", in my nuxt version 3 project. whenever I refresh the page, I see first the fallback page appeared and then the content of the website, here is the config:
pwa: {
registerType: 'autoUpdate',
registerWebManifestInRouteRules: true,
manifest: {
"name": "Fares bazar",
"short_name": "Faresbazar",
"start_url": "/",
"display": "fullscreen",
"background_color": "#ffffff",
"lang": "fa",
"scope": "https://faresbazar.com",
"theme_color": "#d71920",
"icons": [
{
"src": "faresbazar-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "faresbazar-512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"description": "جدیدترین و خوشنامترین محصولات دیجیتال را براحتی از طریق نرمافزار فارِس بازار خرید نمایید.",
"dir": "auto",
"display_override": [
"fullscreen",
"standalone"
],
"categories": [
"shopping"
],
"screenshots": [
{
"src": "screenshot.png",
"sizes": "1280x800",
"type": "image/png"
},
{
"src": "screenshot.png",
"sizes": "750x1334",
"type": "image/png"
}
]
},
workbox: {
navigateFallback: 'fallback',
globPatterns: ['**/*.{js,css,html,png,svg,ico}'
],
},
client: {
installPrompt: true,
// you don't need to include this: only for testing purposes
// if enabling periodic sync for update use 16 minutes or so (periodicSyncForUpdates: 60*15)
periodicSyncForUpdates: 3600,
},
},
clearing site data didn't solve my problem. the project contains multiple routes and pages. showing fallback page is not specific to one page
Hey everyone, great job on the plugin, it's been super useful!
While working on my PWA and this plugin I had a lot of confusion around how to get Push Notifications working, I had a hard time finding the information I needed in the docs so I just wanted to share my thoughts here.
When Googling "vite pwa push notifications", these are the results I get:
You get the idea.
This page is the only mention of push notifications in the docs.
This links to a page that I don't think exists anymore in the Workbox docs (It redirects to this homepage https://web.dev/explore/notifications).
And it also links to the Elk app repository, which is a really good implementation, but it's also a huge and extremely complicated app which is sure to overwhelm anyone that doesn't know what they're looking at.
I understand that the docs are trying to push people to read the entirety of the Workbox docs to implement notifications, but to me that seems really overkill.
Push Notifications really only require two listeners, it shouldn't require a developer to learn how to use Workbox in its entirety before they can implement it. After all, we don't expect every developer that use vite-pwa
to understand what's going on in their service worker when they first install the plugin, so why should it be different for adding notifications?
Push notifications are arguably the # 1 reason people want to make a PWA, so why make it so difficult for people to find the answer they need?
From this there's a couple of things that I think are missing:
I think we can all agree on the fact that we want PWA adoption to increase, I think doing this will improve the developer experience massively and lower the barrier of entry to making PWAs.
I'm in no way an expert with service workers, however this is my current service worker implementation in Typescript (pieced together from Googling and the Elk repository). If nobody else has a better example I'd love if this was added to the docs.
// ./service-worker/sw.ts
/// <reference lib="WebWorker" />
/// <reference types="vite/client" />
import {
cleanupOutdatedCaches,
createHandlerBoundToURL,
precacheAndRoute,
} from "workbox-precaching";
import { NavigationRoute, registerRoute } from "workbox-routing";
declare const self: ServiceWorkerGlobalScope;
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") self.skipWaiting();
});
const entries = self.__WB_MANIFEST;
precacheAndRoute(entries);
// clean old assets
cleanupOutdatedCaches();
// only cache pages and external assets on local build + start or in production
if (import.meta.env.PROD) {
// to allow work offline
registerRoute(new NavigationRoute(createHandlerBoundToURL("index.html")));
}
self.addEventListener("push", onPush);
self.addEventListener("notificationclick", onNotificationClick);
export function onPush(event: PushEvent) {
console.log("[Service Worker] Push Received.");
if (event.data) {
const { title, ...rest } = event.data.json();
event.waitUntil(
self.registration.showNotification(title, {
...rest,
})
);
}
}
export function onNotificationClick(event: NotificationEvent) {
const reactToNotificationClick = new Promise((resolve) => {
event.notification.close();
resolve(openUrl(event.notification.data.url));
});
event.waitUntil(reactToNotificationClick);
}
function findBestClient(clients: WindowClient[]) {
const focusedClient = clients.find((client) => client.focused);
const visibleClient = clients.find(
(client) => client.visibilityState === "visible"
);
return focusedClient || visibleClient || clients[0];
}
async function openUrl(url: string) {
const clients = await self.clients.matchAll({ type: "window" });
// Chrome 42-48 does not support navigate
if (clients.length !== 0 && "navigate" in clients[0]) {
const client = findBestClient(clients as WindowClient[]);
await client.navigate(url).then((client) => client?.focus());
}
await self.clients.openWindow(url);
}
And this is my Vite config:
VitePWA({
strategies: "injectManifest",
srcDir: "./service-worker",
filename: "sw.ts",
scope: "/",
devOptions: {
enabled: mode === "development",
},
// ... other configs here
})
For the record, I'm fully willing to write the documentation page myself if given the go-ahead.
I followed the React type declarations docs.
Since migrating to Nx 16.4.0 (which adds type check to vite builder), I have the following error while building my app:
Cannot find type definition file for 'vite-plugin-pwa/react'.
The file is in the program because:
Entry point of type library 'vite-plugin-pwa/react' specified in compilerOptions
With a config as simple as:
"compilerOptions": {
"types": ["node", "vite/client", "vitest", "vite-plugin-pwa/react"],
},
We have an app in React, I have added the following configuration to the vite.config.js
and when I build the application it properly generates the Service worker in the build folder.
If I serve the builded app on localhost I see all the resources to be pre-cached being downloaded and by changing page I see the lazy loaded assets being served from the cache through the ServiceWorker.
However if I reload the window, the assets are still being fetched from the server instead of being retrieved from the cache.
How can I fix it?
NOTE:
html
to the globPatterns
.index.html
(why?) and registerSw.js
but both have the __WB_REVISION__
appended, don't know whyHere is my config:
plugins: [
// ... other plugins
VitePWA({
registerType: "autoUpdate",
workbox: {
globPatterns: ["**/*.{js,css,wasm}"],
},
devOptions: {
enabled: true,
},
});
]
Thanks
Hi, I'm following the instructions for Nuxt 3 on the docs and nuxt generate isn't creating a manifest.webmanifest file in .output/public.
Can you help me understand why?
Here is a minimal example built from the documentation.
nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
ssr: false,
modules: ["@vite-pwa/nuxt"], // https://vite-pwa-org.netlify.app/frameworks/nuxt
pwa: {
/* your pwa options */
},
generate: {
routes: ["/"],
},
});
I run with npm run generate && npx serve .output/public
and when Firefox loads the site, the web server 404's for the manifest.webmanifest
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 GET /200
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 Returned 200 in 1 ms
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 GET /404
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 Returned 200 in 1 ms
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 GET /
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 Returned 200 in 0 ms
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 GET /manifest.webmanifest
HTTP 11/8/2023 10:16:54 AM 127.0.0.1 Returned 404 in 1 ms
These files are created:
Provide the largest picture, 512512, and automatically cut it into pictures of other necessary sizes, such as 192192, 64*64
I'm using vite-plugin-pwa
with my React.js
, Typescript
, and SWC
app. I've noticed in the dev tools it doesn't cache my API requests until the second reload. I tried a solution from this link (from StackOverflow) but it didn't help. I implemented this with:
workbox: {
clientsClaim: true,
skipWaiting: true
}
but it still caches the API response on the second reload. I also tried dns-prefetch
and preconnect
(according to the official documentation) with the API host but it had no effect. Is there any workaround for that, I'm using the GenerateSW
method.
hi,
Thanks for your great plugin. I have challenge with caching api requests.
vite-pwa/nuxt is installed on a nuxt 3 project and data is fetched based on api reqest. I want whenever a user get offline, page data get data from the cached api. Although all static files and components are cached successfully, api requests are not cached.
this is url of the website:
And here is the config of pwa in nuxt.config.js file:
pwa: {
registerType: 'autoUpdate',
registerWebManifestInRouteRules: true,
manifest: {
"name": "Fares bazar",
"short_name": "Faresbazar",
"start_url": "/",
"display": "fullscreen",
"background_color": "#ffffff",
"lang": "fa",
"scope": "https://faresbazar.com",
"theme_color": "#d71920",
"icons": [
{
"src": "faresbazar-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "faresbazar-512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"description": "جدیدترین و خوشنامترین محصولات دیجیتال را براحتی از طریق نرمافزار فارِس بازار خرید نمایید.",
"dir": "auto",
"display_override": [
"fullscreen",
"standalone"
],
"categories": [
"shopping"
],
"screenshots": [
{
"src": "screenshot.png",
"sizes": "1280x800",
"type": "image/png"
},
{
"src": "screenshot.png",
"sizes": "750x1334",
"type": "image/png"
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
runtimeCaching: [
{
urlPattern: 'https://api.faresbazar.com/api-frontend/*',
handler: 'NetworkFirst',
options: {
cacheName: 'my-api-cache',
expiration: {
maxEntries: 500,
maxAgeSeconds: 60 * 60 * 24
}
}
}
]
// additionalManifestEntries: [{ url: '/', revision: new Date().getTime().toString() }]
},
client: {
installPrompt: true,
periodicSyncForUpdates: 3600,
},
},
I try to get the backround sync running for a PWA with this config:
workbox: {
runtimeCaching: [
{
handler: "NetworkOnly",
urlPattern: new RegExp("^https://localhost/api/basic_packages$"),
method: "POST",
options: {
backgroundSync: {
name: "postQueue",
options: {
maxRetentionTime: 24 * 60,
},
},
},
},
I clear all local storages and caches and load the application in browser.
I install the application.
I select the checkbox "offline" for serviceworker in devtools of chrome.
The post requests do not end up in the queue.
But if i reload the PWA while offline, it suddenly works.
The matching requests end up in the queue like expceted.
If i use a string instead of the regexp, it works from the beginning without the reload.
What could be the problem?
I want to give the vite-plugin-pwa a try. So I setup a new workspace (npm create vite@latest
) based on vite 5.1.4
But when I then install the vite-plugin-pwa I get some warnings:
npm WARN deprecated [email protected]: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
npm WARN deprecated [email protected]: Please use @jridgewell/sourcemap-codec instead
npm WARN deprecated [email protected]: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
Can I ignore them?
When I use the envPrefix
option for my vite config. The VitePWA
plugin does not reflect that prefix still uses VITE_
as the default
Notice: It works fine during development, but when building it, it doesn't function as expected.
Turn on devtools.enabled
in the default generateSW
strategy, once you load the app you will get the following error in Vite output:
warnings
One of the glob patterns doesn't match any files. Please remove or fix the following: {
"globDirectory": ".../prj/dev-dist",
"globPattern": "**/*.{js,css,html,woff,woff2,ttf,eot,mp3}",
"globIgnores": [
"**/node_modules/**/*",
"sw.js",
"workbox-*.js"
]
}
Hi All,
Hoping someone can help me out, I would like to change the name of the index.html file that is put in dist directory during build.
Is this possible?
Thanks!
getsentry/sentry-javascript-bundler-plugins#460
@ArnauKokoro posted this issue in the getsentry/sentry-javascript-bundler-plugins repo.
Within this issue @iforst writes the following:
getsentry/sentry-javascript-bundler-plugins#460 (comment)
Hi, this is probably a bug somewhere in workbox or VitePWA, would you mind opening an issue in their respective repositories?
You can point them to this comment. My suspicion here is that they are trying to resolve or rewrite the virtual module which they should generally not do since it starts with a null bye \0. This is a convention in rollup/vite that everybody building plugins should adhere to.
Ideally you also share your build logs in case there are any warnings or similar!
Here's what my generated service worker looks like:
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// If the loader is already loaded, just stop.
if (!self.define) {
let registry = {};
// Used for `eval` and `importScripts` where we can't get script URL by other means.
// In both cases, it's safe to use a global var because those functions are synchronous.
let nextDefineUri;
const singleRequire = (uri,parentUri)=>{
uri = new URL(uri + ".js",parentUri).href;
return registry[uri] || (
new Promise(resolve=>{
if ("document"in self) {
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
} else {
nextDefineUri = uri;
importScripts(uri);
resolve();
}
}
)
.then(()=>{
let promise = registry[uri];
if (!promise) {
throw new Error(`Module ${uri} didn’t register its module`);
}
return promise;
}
));
}
;
self.define = (depsNames,factory)=>{
const uri = nextDefineUri || ("document"in self ? document.currentScript.src : "") || location.href;
if (registry[uri]) {
// Module is already loading or loaded.
return;
}
let exports = {};
const require = depUri=>singleRequire(depUri, uri);
const specialDeps = {
module: {
uri
},
exports,
require
};
registry[uri] = Promise.all(depsNames.map(depName=>specialDeps[depName] || require(depName))).then(deps=>{
factory(...deps);
return exports;
}
);
}
;
}
define(['./workbox-ffaa3760'], (function(workbox) {
'use strict';
self.addEventListener('message', event=>{
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
}
);
/**
* The precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
workbox.precacheAndRoute([{
"url": "/",
"revision": "0.ia2na8sk9i"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/"),{
allowlist: [/^\/$/]
}));
}
));
//# sourceMappingURL=sw.js.map
;import "/_nuxt/@id/__x00__sentry-release-injection-file";
The last line ;import "/_nuxt/@id/__x00__sentry-release-injection-file";
is causing the error:
And idea on how we can get vite-pwa to work with Sentry Vite plugin?
So, we got into a pickle with our web app. I migrated from Webpack to Vite, and because it previously had a web manifest and a service worker, I set one up again with vite-pwa.
This caused a problem, because vite-pwa was returning 404 for a /blog
route, because it wasn't a defined route in the router. HOWEVER, it was proxied using NGINX to go to another Wordpress site. But the service worker wouldn't even check, it just returned 404.
After thinking about it, I realized we didn't really need any kind of offline capability and really it was more trouble than it was worth. We've now tried every strategy we can think of to remove it, and we simply cannot.
If I do a Vite production build, for example, with the service worker. And then I change the service worker setup to:
VitePWA({
selfDestroying: true,
// Destroy in dev mode too
devOptions: {
enabled: true
}
}),
...and then we run Vite in dev mode, this does not destroy the service worker at all. Refreshing the page loads the service worker, and the service worker throws a ton of errors saying that a bunch of files have 404s (like .svg
assets), yet all those 404s are for files that should not be retrieved in dev mode. (It's adding hashes to them.)
If we tell users to completely clear the cache, our production site works again. But we can't do that in every case. We just want vite-pwa to not exist anymore, and we can't seem to do anything to remove it. In fact, we tried code like:
void navigator.serviceWorker.getRegistrations().then(function(registrations) {
for (const registration of registrations) {
void registration.unregister()
}
})
...which we got from MDN, and tried using this with vite-pwa not loaded, and the service worker seemed to only re-create itself. I guess, because it was cached, it loaded a cached root HTML file, which loaded the cached service worker?
Please, how do we delete this and never think about it again? Right now it's the zombie that never dies.
The server keeps reloading when a GET request gets send to it, it seams something is triggering a change in the dev-dist\registerSW.js
The server only reloads when I change files...
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import dotenv from 'dotenv'
import { VitePWA } from 'vite-plugin-pwa'
dotenv.config({ path: 'src/config/.env' }) // Load environment variables from .env file
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
require('tailwindcss'),
VitePWA({
// registerType: 'autoUpdate',
devOptions: {
enabled: true,
},
}),
],
})
if ('serviceWorker' in navigator)
navigator.serviceWorker.register('/dev-sw.js?dev-sw', {
scope: '/',
type: 'classic',
})
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// If the loader is already loaded, just stop.
if (!self.define) {
let registry = {}
// Used for `eval` and `importScripts` where we can't get script URL by other means.
// In both cases, it's safe to use a global var because those functions are synchronous.
let nextDefineUri
const singleRequire = (uri, parentUri) => {
uri = new URL(uri + '.js', parentUri).href
return (
registry[uri] ||
new Promise((resolve) => {
if ('document' in self) {
const script = document.createElement('script')
script.src = uri
script.onload = resolve
document.head.appendChild(script)
} else {
nextDefineUri = uri
importScripts(uri)
resolve()
}
}).then(() => {
let promise = registry[uri]
if (!promise) {
throw new Error(`Module ${uri} didn’t register its module`)
}
return promise
})
)
}
self.define = (depsNames, factory) => {
const uri =
nextDefineUri ||
('document' in self ? document.currentScript.src : '') ||
location.href
if (registry[uri]) {
// Module is already loading or loaded.
return
}
let exports = {}
const require = (depUri) => singleRequire(depUri, uri)
const specialDeps = {
module: { uri },
exports,
require,
}
registry[uri] = Promise.all(
depsNames.map((depName) => specialDeps[depName] || require(depName))
).then((deps) => {
factory(...deps)
return exports
})
}
}
define(['./workbox-9637eeee'], function (workbox) {
'use strict'
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting()
}
})
/**
* The precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
workbox.precacheAndRoute(
[
{
url: 'registerSW.js',
revision: '3ca0b8505b4bec776b69afdba2768812',
},
{
url: 'index.html',
revision: '0.7kniv7baauo',
},
],
{}
)
workbox.cleanupOutdatedCaches()
workbox.registerRoute(
new workbox.NavigationRoute(workbox.createHandlerBoundToURL('index.html'), {
allowlist: [/^\/$/],
})
)
})
{
"name": "SysmaWeb",
"short_name": "SysmaWeb",
"start_url": "/login",
"display": "standalone",
"background_color": "#ffffff",
"lang": "en",
"theme_color": "#3176ff",
"scope": "/"
}
I don't know if this is the expected behavior but I feel it's not, maybe I´m missing something (?)
Help needed!
Am facing some issues,
when I switched to offline via network tab
(1) when I navigate to another route, initially it shows the blank page, it works only on refresh
(2) Images are not showing, they are not from assets but hosted on another domain, like for ex - https://images.delta.com/name_of_image.jpg
and my configurations looks like this
pwa: {
strategies: 'generateSW',
injectRegister: 'auto',
registerType: 'autoUpdate',
manifest: {
name: "Testing app",
short_name: "Testing app",
start_url: "/?pwa",
scope: "/",
icons: [
{
src: "maskable_icon.png",
sizes: "384x384",
type: "image/png",
purpose: "maskable"
},
{
src: "android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
purpose: "any"
},
{
src: "android-chrome-256x256.png",
sizes: "256x256",
type: "image/png"
},
{
src: "icon.png",
sizes: "512x512",
type: "image/png"
}
],
theme_color: "#245BA7",
background_color: "#000000",
display: "standalone"
},
workbox: {
navigateFallback: '/',
globPatterns: ['**/*.{js,css,html,png,PNG,svg,jpg,JPG,jpeg}']
},
devOptions: {
enabled: true,
type: "module",
navigateFallback: '/',
}
}
also I pre-rendered the nitro routes
// pre-render the routes
async 'nitro:config'(nitroConfig) {
if (nitroConfig.dev) { return }
const getMenuItem = useMenuNavigation()
const response = await fetch(`${process.env.INTERNAL_API_URL}/api/globalMenuItems`)
const { main_menu } = await response.json()
if (nitroConfig.prerender && nitroConfig.prerender.routes) {
nitroConfig.prerender.routes?.push(...main_menu.map((item) => getMenuItem(item).link))
}
console.log(nitroConfig.prerender, 'nitroConfig.prerender')
}
Sorry, if something I missed or wrong, Can anybody please help ?
I was searching for the Svelte PWA example repo and it took me a while to realize that I needed to search in the vite-plugin-pwa repo.
I would love to see the following change on the docs:
- The Svelte example project can be found on examples/svelte-routify package/directory.
+ The Svelte example project can be found on [examples/svelte-routify](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/svelte-routify) package/directory.
I think this will save people some time.
Thanks!
Create a project with strategy injectedManifest
and any basic service worker utilizing workbox, enable devtools.enabled
and devtools.type: "module"
, and see that there are no debug logs from workbox when you load the app, adding the mode: "development"
setting to VitePWA doesn't help.
Is there any ability to track the progress of the files being updated in the background. Would be great to just see this kind of info, even some of it so that some kind of progress bar can be displayed. Maybe not as detailed as the progress of a specific file has been downloaded but showing even as simple as Currently downloaded 5 of 25 files.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.