fix: add country flag emoji on windows (#2117)
* fix: add country flag emoji on windows * fix: missing file * fix: cache font file on-demand * fix: attempt to fix * fix: working * fix: ordering * fix: ordering * fix: ordering * fix: fixup * fix: fixup * fix: add comment * fix: fix vercel * fix: fix vercel.json * fix: vercel * refactor: refactor
This commit is contained in:
parent
fd6bb63450
commit
f2d752bfc2
|
@ -7,6 +7,7 @@ import { getIntl, trimWhitespace } from './getIntl.js'
|
||||||
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
||||||
const readFile = promisify(fs.readFile)
|
const readFile = promisify(fs.readFile)
|
||||||
const writeFile = promisify(fs.writeFile)
|
const writeFile = promisify(fs.writeFile)
|
||||||
|
const copyFile = promisify(fs.copyFile)
|
||||||
|
|
||||||
// Try 'en-US' first, then 'en' if that doesn't exist
|
// Try 'en-US' first, then 'en' if that doesn't exist
|
||||||
const PREFERRED_LOCALES = [LOCALE, LOCALE.split('-')[0]]
|
const PREFERRED_LOCALES = [LOCALE, LOCALE.split('-')[0]]
|
||||||
|
@ -63,10 +64,20 @@ async function buildManifestJson () {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function buildFlagEmojiFile () {
|
||||||
|
await copyFile(path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'../node_modules/country-flag-emoji-polyfill/dist/TwemojiCountryFlags.woff2'
|
||||||
|
), path.resolve(
|
||||||
|
__dirname, '../static/TwemojiCountryFlags.woff2'
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async function main () {
|
async function main () {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
buildEmojiI18nFile(),
|
buildEmojiI18nFile(),
|
||||||
buildManifestJson()
|
buildManifestJson(),
|
||||||
|
buildFlagEmojiFile()
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ const JSON_TEMPLATE = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: '^/.*\\.(png|css|json|svg|jpe?g|map|txt|gz|webapp)$',
|
src: '^/.*\\.(png|css|json|svg|jpe?g|map|txt|gz|webapp|woff|woff2)$',
|
||||||
headers: {
|
headers: {
|
||||||
'cache-control': 'public,max-age=3600'
|
'cache-control': 'public,max-age=3600'
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"circular-dependency-plugin": "^5.2.2",
|
"circular-dependency-plugin": "^5.2.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
"country-flag-emoji-polyfill": "^0.1.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-dedoupe": "^0.1.1",
|
"css-dedoupe": "^0.1.1",
|
||||||
"emoji-picker-element": "^1.11.1",
|
"emoji-picker-element": "^1.11.1",
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
}
|
}
|
||||||
.compose-autosuggest-list-item-native-emoji {
|
.compose-autosuggest-list-item-native-emoji {
|
||||||
font-family: PinaforeEmoji;
|
font-family: CountryFlagEmojiPolyfill, PinaforeEmoji;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
30
src/routes/_store/observers/countryFlagEmojiPolyfill.js
Normal file
30
src/routes/_store/observers/countryFlagEmojiPolyfill.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { polyfillCountryFlagEmojis } from 'country-flag-emoji-polyfill'
|
||||||
|
import { store } from '../store.js'
|
||||||
|
|
||||||
|
let polyfilled = false
|
||||||
|
|
||||||
|
const COUNTRY_FLAG_FONT_URL = '/TwemojiCountryFlags.woff2'
|
||||||
|
|
||||||
|
export function countryFlagEmojiPolyfill () {
|
||||||
|
if (!polyfilled) {
|
||||||
|
polyfilled = true
|
||||||
|
const numStylesBefore = document.head.querySelectorAll('style').length
|
||||||
|
polyfillCountryFlagEmojis('Twemoji Mozilla', COUNTRY_FLAG_FONT_URL)
|
||||||
|
const numStylesAfter = document.head.querySelectorAll('style').length
|
||||||
|
// if a style was added, then the polyfill was activated
|
||||||
|
const polyfillActivated = numStylesAfter !== numStylesBefore
|
||||||
|
if (polyfillActivated) {
|
||||||
|
const style = document.createElement('style')
|
||||||
|
style.textContent = `
|
||||||
|
@font-face {
|
||||||
|
font-family: CountryFlagEmojiPolyfill;
|
||||||
|
src: url(${JSON.stringify(COUNTRY_FLAG_FONT_URL)});
|
||||||
|
}
|
||||||
|
`
|
||||||
|
document.head.appendChild(style)
|
||||||
|
// "Twemoji Mozilla" is for emoji-picker-element, since it lists that font first.
|
||||||
|
// "CountryFlagEmojiPolyfill" is for us so we can set it before everything else in our own font family lists.
|
||||||
|
}
|
||||||
|
store.set({ polyfilledCountryFlagEmoji: polyfillActivated })
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import { cleanup } from './cleanup.js'
|
||||||
import { wordFilterObservers } from './wordFilterObservers.js'
|
import { wordFilterObservers } from './wordFilterObservers.js'
|
||||||
import { showComposeDialogObservers } from './showComposeDialogObservers.js'
|
import { showComposeDialogObservers } from './showComposeDialogObservers.js'
|
||||||
import { badgeObservers } from './badgeObservers.js'
|
import { badgeObservers } from './badgeObservers.js'
|
||||||
|
import { countryFlagEmojiPolyfill } from './countryFlagEmojiPolyfill.js'
|
||||||
|
|
||||||
// These observers can be lazy-loaded when the user is actually logged in.
|
// These observers can be lazy-loaded when the user is actually logged in.
|
||||||
// Prevents circular dependencies and reduces the size of main.js
|
// Prevents circular dependencies and reduces the size of main.js
|
||||||
|
@ -24,4 +25,5 @@ export function loggedInObservers () {
|
||||||
showComposeDialogObservers()
|
showComposeDialogObservers()
|
||||||
badgeObservers()
|
badgeObservers()
|
||||||
cleanup()
|
cleanup()
|
||||||
|
countryFlagEmojiPolyfill()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,280 @@
|
||||||
import { isEmojiSupported, setCacheHandler } from 'is-emoji-supported'
|
import { isEmojiSupported, setCacheHandler } from 'is-emoji-supported'
|
||||||
import { QuickLRU } from '../_thirdparty/quick-lru/quick-lru.js'
|
import { QuickLRU } from '../_thirdparty/quick-lru/quick-lru.js'
|
||||||
|
import { store } from '../_store/store.js'
|
||||||
|
|
||||||
// avoid recomputing emoji support over and over again
|
// avoid recomputing emoji support over and over again
|
||||||
// use our own LRU since the built-in one grows forever, which is a small memory leak, but still
|
// use our own LRU since the built-in one grows forever, which is a small memory leak, but still
|
||||||
setCacheHandler(new QuickLRU({ maxSize: 500 }))
|
setCacheHandler(new QuickLRU({ maxSize: 500 }))
|
||||||
|
|
||||||
export const testEmojiSupported = isEmojiSupported
|
const COUNTRY_FLAG_EMOJI = new Set(
|
||||||
|
[
|
||||||
|
'🇦🇨',
|
||||||
|
'🇦🇩',
|
||||||
|
'🇦🇪',
|
||||||
|
'🇦🇫',
|
||||||
|
'🇦🇬',
|
||||||
|
'🇦🇮',
|
||||||
|
'🇦🇱',
|
||||||
|
'🇦🇲',
|
||||||
|
'🇦🇴',
|
||||||
|
'🇦🇶',
|
||||||
|
'🇦🇷',
|
||||||
|
'🇦🇸',
|
||||||
|
'🇦🇹',
|
||||||
|
'🇦🇺',
|
||||||
|
'🇦🇼',
|
||||||
|
'🇦🇽',
|
||||||
|
'🇦🇿',
|
||||||
|
'🇧🇦',
|
||||||
|
'🇧🇧',
|
||||||
|
'🇧🇩',
|
||||||
|
'🇧🇪',
|
||||||
|
'🇧🇫',
|
||||||
|
'🇧🇬',
|
||||||
|
'🇧🇭',
|
||||||
|
'🇧🇮',
|
||||||
|
'🇧🇯',
|
||||||
|
'🇧🇱',
|
||||||
|
'🇧🇲',
|
||||||
|
'🇧🇳',
|
||||||
|
'🇧🇴',
|
||||||
|
'🇧🇶',
|
||||||
|
'🇧🇷',
|
||||||
|
'🇧🇸',
|
||||||
|
'🇧🇹',
|
||||||
|
'🇧🇻',
|
||||||
|
'🇧🇼',
|
||||||
|
'🇧🇾',
|
||||||
|
'🇧🇿',
|
||||||
|
'🇨🇦',
|
||||||
|
'🇨🇨',
|
||||||
|
'🇨🇩',
|
||||||
|
'🇨🇫',
|
||||||
|
'🇨🇬',
|
||||||
|
'🇨🇭',
|
||||||
|
'🇨🇮',
|
||||||
|
'🇨🇰',
|
||||||
|
'🇨🇱',
|
||||||
|
'🇨🇲',
|
||||||
|
'🇨🇳',
|
||||||
|
'🇨🇴',
|
||||||
|
'🇨🇵',
|
||||||
|
'🇨🇷',
|
||||||
|
'🇨🇺',
|
||||||
|
'🇨🇻',
|
||||||
|
'🇨🇼',
|
||||||
|
'🇨🇽',
|
||||||
|
'🇨🇾',
|
||||||
|
'🇨🇿',
|
||||||
|
'🇩🇪',
|
||||||
|
'🇩🇬',
|
||||||
|
'🇩🇯',
|
||||||
|
'🇩🇰',
|
||||||
|
'🇩🇲',
|
||||||
|
'🇩🇴',
|
||||||
|
'🇩🇿',
|
||||||
|
'🇪🇦',
|
||||||
|
'🇪🇨',
|
||||||
|
'🇪🇪',
|
||||||
|
'🇪🇬',
|
||||||
|
'🇪🇭',
|
||||||
|
'🇪🇷',
|
||||||
|
'🇪🇸',
|
||||||
|
'🇪🇹',
|
||||||
|
'🇪🇺',
|
||||||
|
'🇫🇮',
|
||||||
|
'🇫🇯',
|
||||||
|
'🇫🇰',
|
||||||
|
'🇫🇲',
|
||||||
|
'🇫🇴',
|
||||||
|
'🇫🇷',
|
||||||
|
'🇬🇦',
|
||||||
|
'🇬🇧',
|
||||||
|
'🇬🇩',
|
||||||
|
'🇬🇪',
|
||||||
|
'🇬🇫',
|
||||||
|
'🇬🇬',
|
||||||
|
'🇬🇭',
|
||||||
|
'🇬🇮',
|
||||||
|
'🇬🇱',
|
||||||
|
'🇬🇲',
|
||||||
|
'🇬🇳',
|
||||||
|
'🇬🇵',
|
||||||
|
'🇬🇶',
|
||||||
|
'🇬🇷',
|
||||||
|
'🇬🇸',
|
||||||
|
'🇬🇹',
|
||||||
|
'🇬🇺',
|
||||||
|
'🇬🇼',
|
||||||
|
'🇬🇾',
|
||||||
|
'🇭🇰',
|
||||||
|
'🇭🇲',
|
||||||
|
'🇭🇳',
|
||||||
|
'🇭🇷',
|
||||||
|
'🇭🇹',
|
||||||
|
'🇭🇺',
|
||||||
|
'🇮🇨',
|
||||||
|
'🇮🇩',
|
||||||
|
'🇮🇪',
|
||||||
|
'🇮🇱',
|
||||||
|
'🇮🇲',
|
||||||
|
'🇮🇳',
|
||||||
|
'🇮🇴',
|
||||||
|
'🇮🇶',
|
||||||
|
'🇮🇷',
|
||||||
|
'🇮🇸',
|
||||||
|
'🇮🇹',
|
||||||
|
'🇯🇪',
|
||||||
|
'🇯🇲',
|
||||||
|
'🇯🇴',
|
||||||
|
'🇯🇵',
|
||||||
|
'🇰🇪',
|
||||||
|
'🇰🇬',
|
||||||
|
'🇰🇭',
|
||||||
|
'🇰🇮',
|
||||||
|
'🇰🇲',
|
||||||
|
'🇰🇳',
|
||||||
|
'🇰🇵',
|
||||||
|
'🇰🇷',
|
||||||
|
'🇰🇼',
|
||||||
|
'🇰🇾',
|
||||||
|
'🇰🇿',
|
||||||
|
'🇱🇦',
|
||||||
|
'🇱🇧',
|
||||||
|
'🇱🇨',
|
||||||
|
'🇱🇮',
|
||||||
|
'🇱🇰',
|
||||||
|
'🇱🇷',
|
||||||
|
'🇱🇸',
|
||||||
|
'🇱🇹',
|
||||||
|
'🇱🇺',
|
||||||
|
'🇱🇻',
|
||||||
|
'🇱🇾',
|
||||||
|
'🇲🇦',
|
||||||
|
'🇲🇨',
|
||||||
|
'🇲🇩',
|
||||||
|
'🇲🇪',
|
||||||
|
'🇲🇫',
|
||||||
|
'🇲🇬',
|
||||||
|
'🇲🇭',
|
||||||
|
'🇲🇰',
|
||||||
|
'🇲🇱',
|
||||||
|
'🇲🇲',
|
||||||
|
'🇲🇳',
|
||||||
|
'🇲🇴',
|
||||||
|
'🇲🇵',
|
||||||
|
'🇲🇶',
|
||||||
|
'🇲🇷',
|
||||||
|
'🇲🇸',
|
||||||
|
'🇲🇹',
|
||||||
|
'🇲🇺',
|
||||||
|
'🇲🇻',
|
||||||
|
'🇲🇼',
|
||||||
|
'🇲🇽',
|
||||||
|
'🇲🇾',
|
||||||
|
'🇲🇿',
|
||||||
|
'🇳🇦',
|
||||||
|
'🇳🇨',
|
||||||
|
'🇳🇪',
|
||||||
|
'🇳🇫',
|
||||||
|
'🇳🇬',
|
||||||
|
'🇳🇮',
|
||||||
|
'🇳🇱',
|
||||||
|
'🇳🇴',
|
||||||
|
'🇳🇵',
|
||||||
|
'🇳🇷',
|
||||||
|
'🇳🇺',
|
||||||
|
'🇳🇿',
|
||||||
|
'🇴🇲',
|
||||||
|
'🇵🇦',
|
||||||
|
'🇵🇪',
|
||||||
|
'🇵🇫',
|
||||||
|
'🇵🇬',
|
||||||
|
'🇵🇭',
|
||||||
|
'🇵🇰',
|
||||||
|
'🇵🇱',
|
||||||
|
'🇵🇲',
|
||||||
|
'🇵🇳',
|
||||||
|
'🇵🇷',
|
||||||
|
'🇵🇸',
|
||||||
|
'🇵🇹',
|
||||||
|
'🇵🇼',
|
||||||
|
'🇵🇾',
|
||||||
|
'🇶🇦',
|
||||||
|
'🇷🇪',
|
||||||
|
'🇷🇴',
|
||||||
|
'🇷🇸',
|
||||||
|
'🇷🇺',
|
||||||
|
'🇷🇼',
|
||||||
|
'🇸🇦',
|
||||||
|
'🇸🇧',
|
||||||
|
'🇸🇨',
|
||||||
|
'🇸🇩',
|
||||||
|
'🇸🇪',
|
||||||
|
'🇸🇬',
|
||||||
|
'🇸🇭',
|
||||||
|
'🇸🇮',
|
||||||
|
'🇸🇯',
|
||||||
|
'🇸🇰',
|
||||||
|
'🇸🇱',
|
||||||
|
'🇸🇲',
|
||||||
|
'🇸🇳',
|
||||||
|
'🇸🇴',
|
||||||
|
'🇸🇷',
|
||||||
|
'🇸🇸',
|
||||||
|
'🇸🇹',
|
||||||
|
'🇸🇻',
|
||||||
|
'🇸🇽',
|
||||||
|
'🇸🇾',
|
||||||
|
'🇸🇿',
|
||||||
|
'🇹🇦',
|
||||||
|
'🇹🇨',
|
||||||
|
'🇹🇩',
|
||||||
|
'🇹🇫',
|
||||||
|
'🇹🇬',
|
||||||
|
'🇹🇭',
|
||||||
|
'🇹🇯',
|
||||||
|
'🇹🇰',
|
||||||
|
'🇹🇱',
|
||||||
|
'🇹🇲',
|
||||||
|
'🇹🇳',
|
||||||
|
'🇹🇴',
|
||||||
|
'🇹🇷',
|
||||||
|
'🇹🇹',
|
||||||
|
'🇹🇻',
|
||||||
|
'🇹🇼',
|
||||||
|
'🇹🇿',
|
||||||
|
'🇺🇦',
|
||||||
|
'🇺🇬',
|
||||||
|
'🇺🇲',
|
||||||
|
'🇺🇳',
|
||||||
|
'🇺🇸',
|
||||||
|
'🇺🇾',
|
||||||
|
'🇺🇿',
|
||||||
|
'🇻🇦',
|
||||||
|
'🇻🇨',
|
||||||
|
'🇻🇪',
|
||||||
|
'🇻🇬',
|
||||||
|
'🇻🇮',
|
||||||
|
'🇻🇳',
|
||||||
|
'🇻🇺',
|
||||||
|
'🇼🇫',
|
||||||
|
'🇼🇸',
|
||||||
|
'🇽🇰',
|
||||||
|
'🇾🇪',
|
||||||
|
'🇾🇹',
|
||||||
|
'🇿🇦',
|
||||||
|
'🇿🇲',
|
||||||
|
'🇿🇼',
|
||||||
|
'🏴',
|
||||||
|
'🏴',
|
||||||
|
'🏴'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
export function testEmojiSupported (unicode) {
|
||||||
|
if (store.get().polyfilledCountryFlagEmoji && COUNTRY_FLAG_EMOJI.has(unicode)) {
|
||||||
|
return true // just assume it's supported; is-emoji-supported doesn't work in this case
|
||||||
|
}
|
||||||
|
return isEmojiSupported(unicode)
|
||||||
|
}
|
||||||
|
|
|
@ -97,10 +97,6 @@ input, textarea {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
|
||||||
font-family: system-ui, -apple-system, PinaforeRegular, sans-serif, PinaforeEmoji;
|
|
||||||
}
|
|
||||||
|
|
||||||
button, .button {
|
button, .button {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
background: var(--button-bg);
|
background: var(--button-bg);
|
||||||
|
@ -164,7 +160,7 @@ input:required, input:invalid {
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
font-family: inherit;
|
font-family: CountryFlagEmojiPolyfill, system-ui, -apple-system, PinaforeRegular, sans-serif, PinaforeEmoji;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
@ -208,5 +204,5 @@ textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline-emoji {
|
.inline-emoji {
|
||||||
font-family: PinaforeEmoji, sans-serif;
|
font-family: CountryFlagEmojiPolyfill, PinaforeEmoji, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@ const ON_DEMAND_CACHE = [
|
||||||
{
|
{
|
||||||
regex: /\$polyfill\$/,
|
regex: /\$polyfill\$/,
|
||||||
cache: WEBPACK_ASSETS
|
cache: WEBPACK_ASSETS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: /TwemojiCountryFlags\.woff2/,
|
||||||
|
cache: ASSETS
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -34,6 +38,7 @@ const assets = __assets__
|
||||||
.filter(filename => !filename.endsWith('.webapp')) // KaiOS manifest
|
.filter(filename => !filename.endsWith('.webapp')) // KaiOS manifest
|
||||||
.filter(filename => !/emoji-.*?\.json$/.test(filename)) // useless to cache; it already goes in IndexedDB
|
.filter(filename => !/emoji-.*?\.json$/.test(filename)) // useless to cache; it already goes in IndexedDB
|
||||||
.filter(filename => !/screenshot-.*?\.png/.test(filename)) // only used during PWA installation, don't bother caching
|
.filter(filename => !/screenshot-.*?\.png/.test(filename)) // only used during PWA installation, don't bother caching
|
||||||
|
.filter(filename => !/TwemojiCountryFlags\.woff2/.test(filename)) // cache on-demand
|
||||||
|
|
||||||
// `shell` is an array of all the files generated by webpack
|
// `shell` is an array of all the files generated by webpack
|
||||||
// also contains '/index.html' for some reason
|
// also contains '/index.html' for some reason
|
||||||
|
|
BIN
static/TwemojiCountryFlags.woff2
Normal file
BIN
static/TwemojiCountryFlags.woff2
Normal file
Binary file not shown.
|
@ -36,7 +36,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "^/.*\\.(png|css|json|svg|jpe?g|map|txt|gz|webapp)$",
|
"src": "^/.*\\.(png|css|json|svg|jpe?g|map|txt|gz|webapp|woff|woff2)$",
|
||||||
"headers": {
|
"headers": {
|
||||||
"cache-control": "public,max-age=3600"
|
"cache-control": "public,max-age=3600"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2415,6 +2415,13 @@ cosmiconfig@^7.0.0:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
yaml "^1.10.0"
|
yaml "^1.10.0"
|
||||||
|
|
||||||
|
country-flag-emoji-polyfill@^0.1.1:
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/country-flag-emoji-polyfill/-/country-flag-emoji-polyfill-0.1.1.tgz#1fab7b364c2631f7e7949fbd98659552f401596e"
|
||||||
|
integrity sha512-H4iB8BAnlcLxE9mxVXm9vY28zKtqjEYRCO+vz1x4u6IsmomHQd/EQfR/Py0YmxeVYkBAOUPJBcY3KJPd+BQe6Q==
|
||||||
|
dependencies:
|
||||||
|
is-emoji-supported "^0.0.5"
|
||||||
|
|
||||||
cross-env@^7.0.3:
|
cross-env@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||||
|
|
Loading…
Reference in a new issue