Reduce pwa consumption
parent
35046b400b
commit
e17c84882f
|
@ -1,6 +1,6 @@
|
|||
.env
|
||||
source/data/*
|
||||
!source/data/versement-mobilité.json
|
||||
source/public/data/*
|
||||
!source/public/data/versement-mobilité.json
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
cypress/downloads
|
||||
|
|
|
@ -7,6 +7,7 @@ const dataDir = join(
|
|||
'..',
|
||||
'..',
|
||||
'source',
|
||||
'public',
|
||||
'data'
|
||||
)
|
||||
|
||||
|
|
|
@ -15,8 +15,10 @@ import {
|
|||
configSituationSelector,
|
||||
situationSelector,
|
||||
} from '@/selectors/simulationSelectors'
|
||||
import { ErrorBoundary } from '@sentry/react'
|
||||
import { FallbackRender } from '@sentry/react/types/errorboundary'
|
||||
import rules from 'modele-social'
|
||||
import { StrictMode, useContext, useMemo } from 'react'
|
||||
import { ComponentProps, StrictMode, useContext, useMemo } from 'react'
|
||||
import { Helmet } from 'react-helmet-async'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
@ -34,6 +36,7 @@ import Iframes from './pages/Iframes'
|
|||
import Integration from './pages/integration/index'
|
||||
import Landing from './pages/Landing/Landing'
|
||||
import Nouveautés from './pages/Nouveautes/Nouveautes'
|
||||
import Offline from './pages/Offline'
|
||||
import Simulateurs from './pages/Simulateurs'
|
||||
import Stats from './pages/Stats/LazyStats'
|
||||
import Provider, { ProviderProps } from './Provider'
|
||||
|
@ -106,6 +109,14 @@ const Router = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const CatchOffline = ({ error }: ComponentProps<FallbackRender>) => {
|
||||
if (error.message.includes('Failed to fetch dynamically imported module')) {
|
||||
return <Offline />
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const { t } = useTranslation()
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
|
@ -119,32 +130,35 @@ const App = () => {
|
|||
/>
|
||||
|
||||
<Container>
|
||||
{/* Passing location down to prevent update blocking */}
|
||||
<Switch>
|
||||
<Route path={sitePaths.créer.index} component={Créer} />
|
||||
<Route path={sitePaths.gérer.index} component={Gérer} />
|
||||
<Route path={sitePaths.simulateurs.index} component={Simulateurs} />
|
||||
<Route
|
||||
path={sitePaths.documentation.index}
|
||||
component={Documentation}
|
||||
/>
|
||||
<Route path={sitePaths.développeur.index} component={Integration} />
|
||||
<Route path={sitePaths.nouveautés} component={Nouveautés} />
|
||||
<CompatRoute path={sitePaths.stats} component={Stats} />
|
||||
<Route path={sitePaths.budget} component={Budget} />
|
||||
<Route path={sitePaths.accessibilité} component={Accessibilité} />
|
||||
<ErrorBoundary fallback={CatchOffline}>
|
||||
{/* Passing location down to prevent update blocking */}
|
||||
<Switch>
|
||||
<Route path={sitePaths.créer.index} component={Créer} />
|
||||
<Route path={sitePaths.gérer.index} component={Gérer} />
|
||||
<Route path={sitePaths.simulateurs.index} component={Simulateurs} />
|
||||
<Route
|
||||
path={sitePaths.documentation.index}
|
||||
component={Documentation}
|
||||
/>
|
||||
<Route path={sitePaths.développeur.index} component={Integration} />
|
||||
<Route path={sitePaths.nouveautés} component={Nouveautés} />
|
||||
<CompatRoute path={sitePaths.stats} component={Stats} />
|
||||
<Route path={sitePaths.budget} component={Budget} />
|
||||
<Route path={sitePaths.accessibilité} component={Accessibilité} />
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/dev/integration-test"
|
||||
component={IntegrationTest}
|
||||
/>
|
||||
<Route exact path="/dev/personas" component={Personas} />
|
||||
<Route
|
||||
exact
|
||||
path="/dev/integration-test"
|
||||
component={IntegrationTest}
|
||||
/>
|
||||
<Route exact path="/dev/personas" component={Personas} />
|
||||
|
||||
<Route component={Route404} />
|
||||
</Switch>
|
||||
<Spacing xxl />
|
||||
<Route component={Route404} />
|
||||
</Switch>
|
||||
<Spacing xxl />
|
||||
</ErrorBoundary>
|
||||
</Container>
|
||||
|
||||
{!isEmbedded && <Footer />}
|
||||
</StyledLayout>
|
||||
)
|
||||
|
|
|
@ -96,7 +96,15 @@ async function tauxVersementTransport(
|
|||
codeCommune = '132' + commune.codePostal.slice(-2)
|
||||
}
|
||||
// 2. On récupère le versement transport associé
|
||||
const json = (await import('@/data/versement-mobilité.json')).default
|
||||
const response = await fetch('/data/versement-mobilité.json')
|
||||
if (!response.ok) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(response)
|
||||
|
||||
return 0
|
||||
}
|
||||
const json =
|
||||
(await response.json()) as typeof import('@/public/data/versement-mobilité.json')
|
||||
|
||||
return json[codeCommune as keyof typeof json] ?? 0
|
||||
}
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
import { Appear } from '@/components/ui/animate'
|
||||
import Emoji from '@/components/utils/Emoji'
|
||||
import { SitePathsContext } from '@/components/utils/SitePathsContext'
|
||||
import lastRelease from '@/data/last-release.json'
|
||||
import { Banner, HideButton, InnerBanner } from '@/design-system/banner'
|
||||
import { Link } from '@/design-system/typography/link'
|
||||
import { useFetchData } from '@/hooks/useFetchData'
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { getItem, setItem } from '../../storage/safeLocalStorage'
|
||||
|
||||
const localStorageKey = 'last-viewed-release'
|
||||
|
||||
export const hideNewsBanner = () => {
|
||||
setItem(localStorageKey, lastRelease.name)
|
||||
type LastRelease = typeof import('@/public/data/last-release.json')
|
||||
|
||||
export const useHideNewsBanner = () => {
|
||||
const { data: lastReleaseData } = useFetchData<LastRelease>(
|
||||
'/data/last-release.json'
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (lastReleaseData) {
|
||||
setItem(localStorageKey, lastReleaseData.name)
|
||||
}
|
||||
}, [lastReleaseData])
|
||||
}
|
||||
|
||||
export const determinant = (word: string) =>
|
||||
/^[aeiouy]/i.exec(word) ? 'd’' : 'de '
|
||||
|
||||
export default function NewsBanner() {
|
||||
function NewsBanner({ lastRelease }: { lastRelease: LastRelease }) {
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
const { t } = useTranslation()
|
||||
const lastViewedRelease = getItem(localStorageKey)
|
||||
|
@ -58,3 +67,13 @@ export default function NewsBanner() {
|
|||
</Banner>
|
||||
)
|
||||
}
|
||||
|
||||
export default function NewsBannerWrapper() {
|
||||
const { data: lastReleaseData } = useFetchData<LastRelease>(
|
||||
'/data/last-release.json'
|
||||
)
|
||||
|
||||
return lastReleaseData === null ? null : (
|
||||
<NewsBanner lastRelease={lastReleaseData} />
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
|
||||
export const useFetchData = <T>(url: string) => {
|
||||
const [data, setData] = useState<null | T>(null)
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController()
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const resData = (await response.json()) as T
|
||||
setData(resData)
|
||||
}
|
||||
setLoading(false)
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name !== 'AbortError') {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fetchData()
|
||||
|
||||
return () => {
|
||||
controller.abort()
|
||||
}
|
||||
}, [url])
|
||||
|
||||
return { data, loading }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { determinant, hideNewsBanner } from '@/components/layout/NewsBanner'
|
||||
import { determinant, useHideNewsBanner } from '@/components/layout/NewsBanner'
|
||||
import MoreInfosOnUs from '@/components/MoreInfosOnUs'
|
||||
import Emoji from '@/components/utils/Emoji'
|
||||
import { MarkdownWithAnchorLinks } from '@/components/utils/markdown'
|
||||
|
@ -10,7 +10,8 @@ import { Container, Grid } from '@/design-system/layout'
|
|||
import { H1 } from '@/design-system/typography/heading'
|
||||
import { GenericButtonOrLinkProps, Link } from '@/design-system/typography/link'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
import { useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { useFetchData } from '@/hooks/useFetchData'
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { Navigate, useMatch, useNavigate } from 'react-router-dom-v5-compat'
|
||||
import styled from 'styled-components'
|
||||
import { TrackPage } from '../../ATInternetTracking'
|
||||
|
@ -22,31 +23,21 @@ type ReleasesData = Array<{
|
|||
description: string
|
||||
}>
|
||||
|
||||
type Releases = typeof import('@/public/data/releases.json')
|
||||
|
||||
export default function Nouveautés() {
|
||||
// The release.json file may be big, we don't want to include it in the main
|
||||
// bundle, that's why we only fetch it on this page.
|
||||
const [data, setData] = useState<ReleasesData>([])
|
||||
useEffect(() => {
|
||||
import('@/data/releases.json')
|
||||
.then(({ default: data }) => {
|
||||
setData(data)
|
||||
})
|
||||
.catch((err) =>
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err)
|
||||
)
|
||||
}, [])
|
||||
const { data } = useFetchData<Releases>('/data/releases.json')
|
||||
const navigate = useNavigate()
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
const slug = useMatch(`${sitePaths.nouveautés}/:slug`)?.params?.slug
|
||||
useEffect(hideNewsBanner, [])
|
||||
useHideNewsBanner()
|
||||
|
||||
const releasesWithId = useMemo(
|
||||
() => data && data.map((v, id) => ({ ...v, id })),
|
||||
() => (data && data.map((v, id) => ({ ...v, id }))) ?? [],
|
||||
[data]
|
||||
)
|
||||
|
||||
if (data.length === 0) {
|
||||
if (!data?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { Message } from '@/design-system'
|
||||
import { Grid } from '@/design-system/layout'
|
||||
import { Intro, Body } from '@/design-system/typography/paragraphs'
|
||||
|
||||
export default function Offline() {
|
||||
return (
|
||||
<Grid container css={{ justifyContent: 'center', margin: '10rem 0' }}>
|
||||
<Grid item md={8} sm={12}>
|
||||
<Message type="info" css={{ margin: '1rem 0' }}>
|
||||
<Intro>Vous êtes actuellement hors ligne.</Intro>
|
||||
<Body>
|
||||
Cette page n'a pas encore été téléchargée et n'est donc pas
|
||||
disponible sans internet, pour y accéder vérifiez votre connexion
|
||||
puis rechargez la page.
|
||||
</Body>
|
||||
</Message>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
|
@ -2,11 +2,14 @@ import { H2, H3 } from '@/design-system/typography/heading'
|
|||
import { Link } from '@/design-system/typography/link'
|
||||
import { Li, Ul } from '@/design-system/typography/list'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
import { useFetchData } from '@/hooks/useFetchData'
|
||||
import { useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import stats from '@/data/stats.json'
|
||||
import { StatsStruct } from './types'
|
||||
|
||||
export default function DemandeUtilisateurs() {
|
||||
const { data: stats } = useFetchData<StatsStruct>('/data/stats.json')
|
||||
|
||||
return (
|
||||
<section>
|
||||
<H2 id="demandes-utilisateurs">Demandes utilisateurs</H2>
|
||||
|
@ -22,10 +25,10 @@ export default function DemandeUtilisateurs() {
|
|||
</Body>
|
||||
|
||||
<H3>En attente d'implémentation</H3>
|
||||
<Pagination items={stats.retoursUtilisateurs.open} />
|
||||
<Pagination items={stats?.retoursUtilisateurs.open ?? []} />
|
||||
|
||||
<H3>Réalisées</H3>
|
||||
<Pagination items={stats.retoursUtilisateurs.closed} />
|
||||
<Pagination items={stats?.retoursUtilisateurs.closed ?? []} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ import PagesChart from '@/components/charts/PagesCharts'
|
|||
import InfoBulle from '@/components/ui/InfoBulle'
|
||||
import Emoji from '@/components/utils/Emoji'
|
||||
import { useScrollToHash } from '@/components/utils/markdown'
|
||||
import statsJson from '@/data/stats.json'
|
||||
import { Radio, ToggleGroup } from '@/design-system/field'
|
||||
import { Item, Select } from '@/design-system/field/Select'
|
||||
import { Grid, Spacing } from '@/design-system/layout'
|
||||
import { H2, H3 } from '@/design-system/typography/heading'
|
||||
import { Body, Intro } from '@/design-system/typography/paragraphs'
|
||||
import { useFetchData } from '@/hooks/useFetchData'
|
||||
import { formatValue } from 'publicodes'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Trans } from 'react-i18next'
|
||||
|
@ -24,16 +25,9 @@ import SatisfactionChart from './SatisfactionChart'
|
|||
import { Page, PageChapter2, PageSatisfaction, StatsStruct } from './types'
|
||||
import { formatDay, formatMonth } from './utils'
|
||||
|
||||
const stats = statsJson as unknown as StatsStruct
|
||||
|
||||
type Period = 'mois' | 'jours'
|
||||
type Chapter2 = PageChapter2 | 'PAM'
|
||||
|
||||
const chapters2: Chapter2[] = [
|
||||
...new Set(stats.visitesMois?.pages.map((p) => p.page_chapter2)),
|
||||
'PAM',
|
||||
]
|
||||
|
||||
type Pageish = Page | PageSatisfaction
|
||||
|
||||
const isPAM = (name: string | undefined) =>
|
||||
|
@ -116,7 +110,11 @@ interface BrushStartEndIndex {
|
|||
endIndex?: number
|
||||
}
|
||||
|
||||
const StatsDetail = () => {
|
||||
interface StatsDetailProps {
|
||||
stats: StatsStruct
|
||||
}
|
||||
|
||||
const StatsDetail = ({ stats }: StatsDetailProps) => {
|
||||
const defaultPeriod = 'mois'
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
useScrollToHash()
|
||||
|
@ -185,6 +183,11 @@ const StatsDetail = () => {
|
|||
[slicedVisits]
|
||||
)
|
||||
|
||||
const chapters2: Chapter2[] = [
|
||||
...new Set(stats.visitesMois?.pages.map((p) => p.page_chapter2)),
|
||||
'PAM',
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<H2>Statistiques détaillées</H2>
|
||||
|
@ -306,17 +309,21 @@ const Indicators = styled.div`
|
|||
`
|
||||
|
||||
export default function Stats() {
|
||||
const statsAvailable = stats.visitesMois !== undefined
|
||||
const { data: stats, loading } = useFetchData<StatsStruct>('/data/stats.json')
|
||||
|
||||
const statsAvailable = stats?.visitesMois != null
|
||||
|
||||
return (
|
||||
<>
|
||||
{statsAvailable ? (
|
||||
<>
|
||||
<StatsDetail />
|
||||
<StatsDetail stats={stats} />
|
||||
<GlobalStats stats={stats} />
|
||||
</>
|
||||
) : loading ? (
|
||||
<Intro>Chargement des statistiques...</Intro>
|
||||
) : (
|
||||
<p>Statistiques indisponibles.</p>
|
||||
<Body>Statistiques indisponibles.</Body>
|
||||
)}
|
||||
|
||||
<DemandeUtilisateurs />
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Emoji from '@/components/utils/Emoji'
|
||||
import { ScrollToTop } from '@/components/utils/Scroll'
|
||||
import { SitePathsContext } from '@/components/utils/SitePathsContext'
|
||||
import jobOffers from '@/data/job-offers.json'
|
||||
import { Banner, InnerBanner } from '@/design-system/banner'
|
||||
import { Link } from '@/design-system/typography/link'
|
||||
import { useFetchData } from '@/hooks/useFetchData'
|
||||
import { useContext } from 'react'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { Routes, Route, useLocation } from 'react-router-dom-v5-compat'
|
||||
import { Route, Routes, useLocation } from 'react-router-dom-v5-compat'
|
||||
import { TrackChapter } from '../../ATInternetTracking'
|
||||
import API from './API'
|
||||
import Iframe from './Iframe'
|
||||
|
@ -23,7 +23,8 @@ type JobOffer = {
|
|||
export default function Integration() {
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
const { pathname } = useLocation()
|
||||
const openJobOffer = (jobOffers as Array<JobOffer>)[0]
|
||||
const { data: jobOffers } = useFetchData<JobOffer[]>('/data/job-offers.json')
|
||||
const openJobOffer = jobOffers?.[0]
|
||||
|
||||
return (
|
||||
<TrackChapter chapter1="integration">
|
||||
|
|
|
@ -36,6 +36,24 @@ const HOUR = 60 * 60
|
|||
const DAY = HOUR * 24
|
||||
const YEAR = DAY * 365
|
||||
|
||||
const networkFirstJS = new Route(
|
||||
({ sameOrigin, url }) => {
|
||||
return sameOrigin && /assets\/.*\.js$/.test(url.pathname)
|
||||
},
|
||||
new NetworkFirst({
|
||||
cacheName: 'js-cache',
|
||||
plugins: [
|
||||
new ExpirationPlugin({
|
||||
maxAgeSeconds: 30 * DAY,
|
||||
maxEntries: 40,
|
||||
}),
|
||||
],
|
||||
fetchOptions: {},
|
||||
})
|
||||
)
|
||||
|
||||
registerRoute(networkFirstJS)
|
||||
|
||||
const staleWhileRevalidate = new Route(
|
||||
({ request, sameOrigin, url }) => {
|
||||
return (
|
||||
|
@ -77,11 +95,12 @@ registerRoute(networkFirstPolyfill)
|
|||
const networkFirstAPI = new Route(
|
||||
({ sameOrigin, url }) => {
|
||||
return (
|
||||
!sameOrigin &&
|
||||
[
|
||||
'api.recherche-entreprises.fabrique.social.gouv.fr',
|
||||
'geo.api.gouv.fr',
|
||||
].includes(url.hostname)
|
||||
(!sameOrigin &&
|
||||
[
|
||||
'api.recherche-entreprises.fabrique.social.gouv.fr',
|
||||
'geo.api.gouv.fr',
|
||||
].includes(url.hostname)) ||
|
||||
(sameOrigin && /data\/.*\.json$/.test(url.pathname))
|
||||
)
|
||||
},
|
||||
new NetworkFirst({
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"test/**/*.ts",
|
||||
"vite.config.ts",
|
||||
"vite-iframe-script.config.ts",
|
||||
"prerender.ts"
|
||||
"prerender.ts",
|
||||
"vite-pwa-options.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import { Options } from 'vite-plugin-pwa'
|
||||
|
||||
export const pwaOptions: Partial<Options> = {
|
||||
registerType: 'prompt',
|
||||
strategies: 'injectManifest',
|
||||
srcDir: 'source',
|
||||
filename: 'sw.ts',
|
||||
injectManifest: {
|
||||
maximumFileSizeToCacheInBytes: 3000000,
|
||||
manifestTransforms: [
|
||||
(entries) => {
|
||||
const manifest = entries.filter(
|
||||
(entry) => !/assets\/.*(-legacy|lazy_)/.test(entry.url)
|
||||
)
|
||||
|
||||
return { manifest }
|
||||
},
|
||||
],
|
||||
},
|
||||
includeAssets: [
|
||||
'logo-*.png',
|
||||
'fonts/*.{woff,woff2}',
|
||||
'références-images/*.{jpg,png,svg}',
|
||||
],
|
||||
manifest: {
|
||||
start_url: '/',
|
||||
name: 'Mon entreprise',
|
||||
short_name: 'Mon entreprise',
|
||||
description: "L'assistant officiel du créateur d'entreprise",
|
||||
lang: 'fr',
|
||||
orientation: 'portrait-primary',
|
||||
display: 'minimal-ui',
|
||||
theme_color: '#2975d1',
|
||||
background_color: '#ffffff',
|
||||
icons: [
|
||||
{
|
||||
src: '/favicon/android-chrome-192x192-shadow.png?v=2.0',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/favicon/android-chrome-512x512-shadow.png?v=2.0',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
|
@ -11,6 +11,7 @@ import { defineConfig, loadEnv, Plugin } from 'vite'
|
|||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
import shimReactPdf from 'vite-plugin-shim-react-pdf'
|
||||
import { runScriptOnFileChange } from './scripts/runScriptOnFileChange'
|
||||
import { pwaOptions } from './vite-pwa-options'
|
||||
|
||||
const env = (mode: string) => loadEnv(mode, process.cwd(), '')
|
||||
|
||||
|
@ -21,7 +22,18 @@ export default defineConfig(({ command, mode }) => ({
|
|||
},
|
||||
publicDir: 'source/public',
|
||||
build: {
|
||||
sourcemap: true,
|
||||
sourcemap: !true,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
chunkFileNames: (chunkInfo) => {
|
||||
if (chunkInfo.isDynamicEntry) {
|
||||
return 'assets/lazy_[name].[hash].js'
|
||||
}
|
||||
|
||||
return 'assets/[name].[hash].js'
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
|
@ -54,7 +66,7 @@ export default defineConfig(({ command, mode }) => ({
|
|||
"mon-entreprise.urssaf.fr : L'assistant officiel du créateur d'entreprise",
|
||||
description:
|
||||
'Du statut juridique à la première embauche, en passant par la simulation des cotisations, vous trouverez ici toutes les ressources pour démarrer votre activité.',
|
||||
shareImage: 'https://mon-entreprise.urssaf.fr/logo-share.png',
|
||||
shareImage: '/logo-share.png',
|
||||
},
|
||||
infrance: {
|
||||
lang: 'en',
|
||||
|
@ -63,48 +75,11 @@ export default defineConfig(({ command, mode }) => ({
|
|||
'My company in France: A step-by-step guide to start a business in France',
|
||||
description:
|
||||
'Find the type of company that suits you and follow the steps to register your company. Discover the French social security system by simulating your hiring costs. Discover the procedures to hire in France and learn the basics of French labour law.',
|
||||
shareImage:
|
||||
'https://mon-entreprise.urssaf.fr/logo-mycompany-share.png',
|
||||
shareImage: '/logo-mycompany-share.png',
|
||||
},
|
||||
},
|
||||
}),
|
||||
VitePWA({
|
||||
registerType: 'prompt',
|
||||
strategies: 'injectManifest',
|
||||
srcDir: 'source',
|
||||
filename: 'sw.ts',
|
||||
injectManifest: {
|
||||
maximumFileSizeToCacheInBytes: 3000000,
|
||||
},
|
||||
includeAssets: [
|
||||
'logo-*.png',
|
||||
'fonts/*.{woff,woff2}',
|
||||
'références-images/*.{jpg,png,svg}',
|
||||
],
|
||||
manifest: {
|
||||
start_url: '/',
|
||||
name: 'Mon entreprise',
|
||||
short_name: 'Mon entreprise',
|
||||
description: "L'assistant officiel du créateur d'entreprise",
|
||||
lang: 'fr',
|
||||
orientation: 'portrait-primary',
|
||||
display: 'minimal-ui',
|
||||
theme_color: '#2975d1',
|
||||
background_color: '#ffffff',
|
||||
icons: [
|
||||
{
|
||||
src: '/favicon/android-chrome-192x192-shadow.png?v=2.0',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/favicon/android-chrome-512x512-shadow.png?v=2.0',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
VitePWA(pwaOptions),
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
}),
|
||||
|
@ -227,6 +202,7 @@ function multipleSPA(options: MultipleSPAOptions): Plugin {
|
|||
config.build = {
|
||||
...config.build,
|
||||
rollupOptions: {
|
||||
...config.build?.rollupOptions,
|
||||
input: Object.fromEntries(
|
||||
Object.keys(options.sites).map((name) => [
|
||||
name,
|
||||
|
|
Loading…
Reference in New Issue