diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 2fb9ad7943345..51d848de12dc9 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -77,23 +77,6 @@ jobs: steps: - run: exit 0 - testMacOS: - name: macOS (Basic, Production, Acceptance) - runs-on: macos-latest - env: - NEXT_TELEMETRY_DISABLED: 1 - NEXT_TEST_JOB: 1 - HEADLESS: true - - steps: - - uses: actions/checkout@v2 - - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - # Installing dependencies again since OS changed - - run: yarn install --frozen-lockfile --check-files || yarn install --frozen-lockfile --check-files - - run: node run-tests.js test/integration/production/test/index.test.js - - run: node run-tests.js test/integration/basic/test/index.test.js - - run: node run-tests.js test/acceptance/* - testWebpack5: name: webpack 5 (Basic, Production, Acceptance) runs-on: ubuntu-latest diff --git a/.github/workflows/test_macos.yml b/.github/workflows/test_macos.yml new file mode 100644 index 0000000000000..09ff576abd913 --- /dev/null +++ b/.github/workflows/test_macos.yml @@ -0,0 +1,22 @@ +on: + push: + branches: [canary] + +name: Test macOS + +jobs: + testMacOS: + name: macOS (Basic, Production, Acceptance) + runs-on: macos-latest + env: + NEXT_TELEMETRY_DISABLED: 1 + NEXT_TEST_JOB: 1 + HEADLESS: true + + steps: + - uses: actions/checkout@v2 + - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - run: yarn install --frozen-lockfile --check-files || yarn install --frozen-lockfile --check-files + - run: node run-tests.js test/integration/production/test/index.test.js + - run: node run-tests.js test/integration/basic/test/index.test.js + - run: node run-tests.js test/acceptance/* diff --git a/docs/api-reference/cli.md b/docs/api-reference/cli.md index badf0e9510376..e97d2b2d59a4d 100644 --- a/docs/api-reference/cli.md +++ b/docs/api-reference/cli.md @@ -48,6 +48,14 @@ NODE_OPTIONS='--inspect' next The first load is colored green, yellow, or red. Aim for green for performant applications. +You can enable production profiling for React with the `--profile` flag in `next build`. This requires Next.js 9.5: + +```bash +next build --profile +``` + +After that, you can use the profiler in the same way as you would in development. + ## Development `next dev` starts the application in development mode with hot-code reloading, error reporting, and more: diff --git a/docs/api-reference/next.config.js/runtime-configuration.md b/docs/api-reference/next.config.js/runtime-configuration.md index 4a4a2a5ace6e1..b52e3e8898560 100644 --- a/docs/api-reference/next.config.js/runtime-configuration.md +++ b/docs/api-reference/next.config.js/runtime-configuration.md @@ -6,8 +6,6 @@ description: Add client and server runtime configuration to your Next.js app. > Generally you'll want to use [build-time environment variables](/docs/api-reference/next.config.js/environment-variables.md) to provide your configuration. The reason for this is that runtime configuration adds rendering / initialization overhead and is incompatible with [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md). -> Runtime configuration is not available when using the [`serverless` target](/docs/api-reference/next.config.js/build-target.md#serverless-target). - To add runtime configuration to your app open `next.config.js` and add the `publicRuntimeConfig` and `serverRuntimeConfig` configs: ```js diff --git a/docs/basic-features/built-in-css-support.md b/docs/basic-features/built-in-css-support.md index c40249a082631..ee44a2bbf47e0 100644 --- a/docs/basic-features/built-in-css-support.md +++ b/docs/basic-features/built-in-css-support.md @@ -117,6 +117,13 @@ npm install sass Sass support has the same benefits and restrictions as the built-in CSS support detailed above. +> **Note**: Sass supports [two different syntaxes](https://sass-lang.com/documentation/syntax), each with their own extension. +> The `.scss` extension requires you use the [SCSS syntax](https://sass-lang.com/documentation/syntax#scss), +> while the `.sass` extension requires you use the [Indented Syntax ("Sass")](https://sass-lang.com/documentation/syntax#the-indented-syntax). +> +> If you're not sure which to choose, start with the `.scss` extension which is a superset of CSS, and doesn't require you learn the +> Indented Syntax ("Sass"). + ### Customizing Sass Options If you want to configure the Sass compiler you can do so by using `sassOptions` in `next.config.js`. diff --git a/errors/invalid-external-rewrite.md b/errors/invalid-external-rewrite.md new file mode 100644 index 0000000000000..89d114af835bf --- /dev/null +++ b/errors/invalid-external-rewrite.md @@ -0,0 +1,13 @@ +# Invalid External Rewrite + +#### Why This Error Occurred + +A rewrite was defined with both `basePath: false` and an internal `destination`. Rewrites that capture urls outside of the `basePath` must route externally, as they are intended for proxying in the case of incremental adoption of Next.js in a project. + +#### Possible Ways to Fix It + +Look for any rewrite where `basePath` is `false` and make sure its `destination` starts with `http://` or `https://`. + +### Useful Links + +- [Rewrites section in Documentation](https://nextjs.org/docs/api-reference/next.config.js/rewrites) diff --git a/examples/blog-starter-typescript/components/alert.tsx b/examples/blog-starter-typescript/components/alert.tsx index 9e07d7736c30c..f804ff6192868 100644 --- a/examples/blog-starter-typescript/components/alert.tsx +++ b/examples/blog-starter-typescript/components/alert.tsx @@ -18,7 +18,7 @@ const Alert = ({ preview }: Props) => {
{JSON.stringify(serverRuntimeConfig)}
+{JSON.stringify(publicRuntimeConfig)}
+hi fallback
+ } + + return ( + <> +Post: {post}
+ time: {time} +hi fallback
+ } + + return ( + <> +Post: {post}
+ time: {time} +hi fallback
+ } + + return ( + <> +Post: {post}
+ time: {time} +hello blocking {time.toString()}
+} + +export default Page diff --git a/test/integration/prerender/test/index.test.js b/test/integration/prerender/test/index.test.js index b47d5d6b88bc5..67a1e8eee22c1 100644 --- a/test/integration/prerender/test/index.test.js +++ b/test/integration/prerender/test/index.test.js @@ -142,6 +142,16 @@ const expectedManifestRoutes = () => ({ initialRevalidateSeconds: 1, srcRoute: null, }, + '/blocking-fallback-some/a': { + dataRoute: `/_next/data/${buildId}/blocking-fallback-some/a.json`, + initialRevalidateSeconds: 1, + srcRoute: '/blocking-fallback-some/[slug]', + }, + '/blocking-fallback-some/b': { + dataRoute: `/_next/data/${buildId}/blocking-fallback-some/b.json`, + initialRevalidateSeconds: 1, + srcRoute: '/blocking-fallback-some/[slug]', + }, '/blog': { dataRoute: `/_next/data/${buildId}/blog.json`, initialRevalidateSeconds: 10, @@ -418,6 +428,20 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(html).toMatch(/Post:.*?post-1/) }) + it('should SSR blocking path correctly (blocking)', async () => { + const html = await renderViaHTTP(appPort, '/blocking-fallback/random-path') + const $ = cheerio.load(html) + expect(JSON.parse($('#__NEXT_DATA__').text()).isFallback).toBe(false) + expect($('p').text()).toBe('Post: random-path') + }) + + it('should SSR blocking path correctly (pre-rendered)', async () => { + const html = await renderViaHTTP(appPort, '/blocking-fallback-some/a') + const $ = cheerio.load(html) + expect(JSON.parse($('#__NEXT_DATA__').text()).isFallback).toBe(false) + expect($('p').text()).toBe('Post: a') + }) + it('should have gsp in __NEXT_DATA__', async () => { const html = await renderViaHTTP(appPort, '/') const $ = cheerio.load(html) @@ -729,6 +753,11 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(html).toMatch(/About:.*?en/) }) + it("should allow rewriting to SSG page with fallback: 'blocking'", async () => { + const html = await renderViaHTTP(appPort, '/blocked-create') + expect(html).toMatch(/Post:.*?blocked-create/) + }) + it('should fetch /_next/data correctly with mismatched href and as', async () => { const browser = await webdriver(appPort, '/') @@ -825,6 +854,28 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(JSON.parse($2('#__NEXT_DATA__').text()).isFallback).toBe(false) }) + it('should never show fallback for page not in getStaticPaths when blocking', async () => { + const html = await renderViaHTTP(appPort, '/blocking-fallback-some/asf') + const $ = cheerio.load(html) + expect(JSON.parse($('#__NEXT_DATA__').text()).isFallback).toBe(false) + + // make another request to ensure it still is + const html2 = await renderViaHTTP(appPort, '/blocking-fallback-some/asf') + const $2 = cheerio.load(html2) + expect(JSON.parse($2('#__NEXT_DATA__').text()).isFallback).toBe(false) + }) + + it('should not show fallback for page in getStaticPaths when blocking', async () => { + const html = await renderViaHTTP(appPort, '/blocking-fallback-some/b') + const $ = cheerio.load(html) + expect(JSON.parse($('#__NEXT_DATA__').text()).isFallback).toBe(false) + + // make another request to ensure it's still not + const html2 = await renderViaHTTP(appPort, '/blocking-fallback-some/b') + const $2 = cheerio.load(html2) + expect(JSON.parse($2('#__NEXT_DATA__').text()).isFallback).toBe(false) + }) + it('should log error in console and browser in dev mode', async () => { const origContent = await fs.readFile(indexPage, 'utf8') @@ -964,6 +1015,11 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(html).toContain('"isFallback":true') }) + it('should not fallback before invalid JSON is returned from getStaticProps when blocking fallback', async () => { + const html = await renderViaHTTP(appPort, '/non-json-blocking/foobar') + expect(html).toContain('"isFallback":false') + }) + it('should show error for invalid JSON returned from getStaticProps on SSR', async () => { const browser = await webdriver(appPort, '/non-json/direct') @@ -1057,6 +1113,42 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ), page: '/bad-ssr', }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/blocking\\-fallback\\/([^\\/]+?)\\.json$` + ), + namedDataRouteRegex: `^/_next/data/${escapeRegex( + buildId + )}/blocking\\-fallback/(?[^/]+?)\\.json$`, + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/non\\-json\\-blocking\\/([^\\/]+?)\\.json$` + ), + page: '/non-json-blocking/[p]', + routeKeys: { + p: 'p', + }, + }, { dataRouteRegex: normalizeRegEx( `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/something.json$` @@ -1247,6 +1353,36 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(manifest.version).toBe(2) expect(manifest.routes).toEqual(expectedManifestRoutes()) expect(manifest.dynamicRoutes).toEqual({ + '/blocking-fallback-once/[slug]': { + dataRoute: `/_next/data/${buildId}/blocking-fallback-once/[slug].json`, + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapedBuildId}\\/blocking\\-fallback\\-once\\/([^\\/]+?)\\.json$` + ), + fallback: null, + routeRegex: normalizeRegEx( + '^\\/blocking\\-fallback\\-once\\/([^\\/]+?)(?:\\/)?$' + ), + }, + '/blocking-fallback-some/[slug]': { + dataRoute: `/_next/data/${buildId}/blocking-fallback-some/[slug].json`, + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapedBuildId}\\/blocking\\-fallback\\-some\\/([^\\/]+?)\\.json$` + ), + fallback: null, + routeRegex: normalizeRegEx( + '^\\/blocking\\-fallback\\-some\\/([^\\/]+?)(?:\\/)?$' + ), + }, + '/blocking-fallback/[slug]': { + dataRoute: `/_next/data/${buildId}/blocking-fallback/[slug].json`, + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapedBuildId}\\/blocking\\-fallback\\/([^\\/]+?)\\.json$` + ), + fallback: null, + routeRegex: normalizeRegEx( + '^\\/blocking\\-fallback\\/([^\\/]+?)(?:\\/)?$' + ), + }, '/blog/[post]': { fallback: '/blog/[post].html', dataRoute: `/_next/data/${buildId}/blog/[post].json`, @@ -1291,6 +1427,16 @@ const runTests = (dev = false, isEmulatedServerless = false) => { fallback: false, routeRegex: normalizeRegEx('^\\/lang\\/([^\\/]+?)\\/about(?:\\/)?$'), }, + '/non-json-blocking/[p]': { + dataRoute: `/_next/data/${buildId}/non-json-blocking/[p].json`, + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapedBuildId}\\/non\\-json\\-blocking\\/([^\\/]+?)\\.json$` + ), + fallback: null, + routeRegex: normalizeRegEx( + '^\\/non\\-json\\-blocking\\/([^\\/]+?)(?:\\/)?$' + ), + }, '/non-json/[p]': { dataRoute: `/_next/data/${buildId}/non-json/[p].json`, dataRouteRegex: normalizeRegEx( @@ -1386,6 +1532,20 @@ const runTests = (dev = false, isEmulatedServerless = false) => { }) if (!isEmulatedServerless) { + it('should not revalidate when set to false in blocking fallback mode', async () => { + const route = '/blocking-fallback-once/test-no-revalidate' + + const initialHtml = await renderViaHTTP(appPort, route) + let newHtml = await renderViaHTTP(appPort, route) + expect(initialHtml).toBe(newHtml) + + newHtml = await renderViaHTTP(appPort, route) + expect(initialHtml).toBe(newHtml) + + newHtml = await renderViaHTTP(appPort, route) + expect(initialHtml).toBe(newHtml) + }) + it('should handle revalidating HTML correctly', async () => { const route = '/blog/post-2/comment-2' const initialHtml = await renderViaHTTP(appPort, route) @@ -1423,6 +1583,80 @@ const runTests = (dev = false, isEmulatedServerless = false) => { expect(newJson).toMatch(/post-2/) expect(newJson).toMatch(/comment-3/) }) + + it('should handle revalidating HTML correctly with blocking', async () => { + const route = '/blocking-fallback/pewpew' + const initialHtml = await renderViaHTTP(appPort, route) + expect(initialHtml).toMatch(/Post:.*?pewpew/) + + let newHtml = await renderViaHTTP(appPort, route) + expect(newHtml).toBe(initialHtml) + + await waitFor(2 * 1000) + await renderViaHTTP(appPort, route) + + await waitFor(2 * 1000) + newHtml = await renderViaHTTP(appPort, route) + expect(newHtml === initialHtml).toBe(false) + expect(newHtml).toMatch(/Post:.*?pewpew/) + }) + + it('should handle revalidating JSON correctly with blocking', async () => { + const route = `/_next/data/${buildId}/blocking-fallback/pewpewdata.json` + const initialJson = await renderViaHTTP(appPort, route) + expect(initialJson).toMatch(/pewpewdata/) + + let newJson = await renderViaHTTP(appPort, route) + expect(newJson).toBe(initialJson) + + await waitFor(2 * 1000) + await renderViaHTTP(appPort, route) + + await waitFor(2 * 1000) + newJson = await renderViaHTTP(appPort, route) + expect(newJson === initialJson).toBe(false) + expect(newJson).toMatch(/pewpewdata/) + }) + + it('should handle revalidating HTML correctly with blocking and seed', async () => { + const route = '/blocking-fallback/a' + const initialHtml = await renderViaHTTP(appPort, route) + const $initial = cheerio.load(initialHtml) + expect($initial('p').text()).toBe('Post: a') + + let newHtml = await renderViaHTTP(appPort, route) + expect(newHtml).toBe(initialHtml) + + await waitFor(2 * 1000) + await renderViaHTTP(appPort, route) + + await waitFor(2 * 1000) + newHtml = await renderViaHTTP(appPort, route) + expect(newHtml === initialHtml).toBe(false) + const $new = cheerio.load(newHtml) + expect($new('p').text()).toBe('Post: a') + }) + + it('should handle revalidating JSON correctly with blocking and seed', async () => { + const route = `/_next/data/${buildId}/blocking-fallback/b.json` + const initialJson = await renderViaHTTP(appPort, route) + expect(JSON.parse(initialJson)).toMatchObject({ + pageProps: { params: { slug: 'b' } }, + }) + + let newJson = await renderViaHTTP(appPort, route) + expect(newJson).toBe(initialJson) + + await waitFor(2 * 1000) + await renderViaHTTP(appPort, route) + + await waitFor(2 * 1000) + newJson = await renderViaHTTP(appPort, route) + expect(newJson === initialJson).toBe(false) + expect(JSON.parse(newJson)).toMatchObject({ + pageProps: { params: { slug: 'b' } }, + }) + }) } it('should not fetch prerender data on mount', async () => { @@ -1487,6 +1721,10 @@ describe('SSG Prerender', () => { { source: '/about', destination: '/lang/en/about' + }, + { + source: '/blocked-create', + destination: '/blocking-fallback/blocked-create', } ] } @@ -1589,6 +1827,10 @@ describe('SSG Prerender', () => { { source: '/about', destination: '/lang/en/about' + }, + { + source: '/blocked-create', + destination: '/blocking-fallback/blocked-create', } ] } @@ -1768,10 +2010,17 @@ describe('SSG Prerender', () => { '/blog/[post]/index.js', '/fallback-only/[slug].js', ] + const fallbackBlockingPages = [ + '/blocking-fallback/[slug].js', + '/blocking-fallback-once/[slug].js', + '/blocking-fallback-some/[slug].js', + '/non-json-blocking/[p].js', + ] const brokenPages = ['/bad-gssp.js', '/bad-ssr.js'] const fallbackTruePageContents = {} + const fallbackBlockingPageContents = {} beforeAll(async () => { exportDir = join(appDir, 'out') @@ -1802,6 +2051,18 @@ describe('SSG Prerender', () => { ) } + for (const page of fallbackBlockingPages) { + const pagePath = join(appDir, 'pages', page) + fallbackBlockingPageContents[page] = await fs.readFile(pagePath, 'utf8') + await fs.writeFile( + pagePath, + fallbackBlockingPageContents[page].replace( + "fallback: 'unstable_blocking'", + 'fallback: false' + ) + ) + } + for (const page of brokenPages) { const pagePath = join(appDir, 'pages', page) await fs.rename(pagePath, `${pagePath}.bak`) @@ -1819,10 +2080,14 @@ describe('SSG Prerender', () => { for (const page of fallbackTruePages) { const pagePath = join(appDir, 'pages', page) - await fs.writeFile(pagePath, fallbackTruePageContents[page]) } + for (const page of fallbackBlockingPages) { + const pagePath = join(appDir, 'pages', page) + await fs.writeFile(pagePath, fallbackBlockingPageContents[page]) + } + for (const page of brokenPages) { const pagePath = join(appDir, 'pages', page) await fs.rename(`${pagePath}.bak`, pagePath) diff --git a/test/unit/webpack-config-overrides.test.js b/test/unit/webpack-config-overrides.test.js new file mode 100644 index 0000000000000..2a0af487e679a --- /dev/null +++ b/test/unit/webpack-config-overrides.test.js @@ -0,0 +1,239 @@ +/* eslint-env jest */ +import { attachReactRefresh } from 'next/dist/build/webpack-config' + +describe('webpack-config attachReactRefresh', () => { + it('should skip adding when unrelated', () => { + const input = { module: { rules: [{ use: 'a' }] } } + const expected = { module: { rules: [{ use: 'a' }] } } + + attachReactRefresh(input, 'rr') + expect(input).toEqual(expected) + }) + + it('should skip adding when existing (shorthand)', () => { + const input = { + module: { + rules: [{ use: ['@next/react-refresh-utils/loader', 'rr'] }], + }, + } + const expected = { + module: { + rules: [{ use: ['@next/react-refresh-utils/loader', 'rr'] }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toEqual(expected) + }) + + it('should skip adding when existing (longhand)', () => { + const input = { + module: { + rules: [ + { use: [require.resolve('@next/react-refresh-utils/loader'), 'rr'] }, + ], + }, + } + const expected = { + module: { + rules: [ + { use: [require.resolve('@next/react-refresh-utils/loader'), 'rr'] }, + ], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toEqual(expected) + }) + + it('should add when missing (single, non-array)', () => { + const input = { + module: { + rules: [{ use: 'rr' }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + expect.stringMatching(/react-refresh-utils[\\/]loader\.js/), + 'rr', + ], + }, + ], + }, + }) + }) + + it('should add when missing (single, array)', () => { + const input = { + module: { + rules: [{ use: ['rr'] }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + expect.stringMatching(/react-refresh-utils[\\/]loader\.js/), + 'rr', + ], + }, + ], + }, + }) + }) + + it('should add when missing (before, array)', () => { + const input = { + module: { + rules: [{ use: ['bla', 'rr'] }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + 'bla', + expect.stringMatching(/react-refresh-utils[\\/]loader\.js/), + 'rr', + ], + }, + ], + }, + }) + }) + + it('should add when missing (after, array)', () => { + const input = { + module: { + rules: [{ use: ['rr', 'bla'] }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + expect.stringMatching(/react-refresh-utils[\\/]loader\.js/), + 'rr', + 'bla', + ], + }, + ], + }, + }) + }) + + it('should add when missing (multi, array)', () => { + const input = { + module: { + rules: [{ use: ['hehe', 'haha', 'rawr', 'rr', 'lol', 'bla'] }], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + 'hehe', + 'haha', + 'rawr', + expect.stringMatching(/react-refresh-utils[\\/]loader\.js/), + 'rr', + 'lol', + 'bla', + ], + }, + ], + }, + }) + }) + + it('should skip when present (multi, array)', () => { + const input = { + module: { + rules: [ + { + use: [ + 'hehe', + 'haha', + '@next/react-refresh-utils/loader', + 'rr', + 'lol', + 'bla', + ], + }, + ], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + 'hehe', + 'haha', + '@next/react-refresh-utils/loader', + 'rr', + 'lol', + 'bla', + ], + }, + ], + }, + }) + }) + + it('should skip when present (multi, array, wrong order)', () => { + const input = { + module: { + rules: [ + { + use: [ + 'hehe', + 'haha', + 'rr', + 'lol', + '@next/react-refresh-utils/loader', + 'bla', + ], + }, + ], + }, + } + + attachReactRefresh(input, 'rr') + expect(input).toMatchObject({ + module: { + rules: [ + { + use: [ + 'hehe', + 'haha', + 'rr', + 'lol', + '@next/react-refresh-utils/loader', + 'bla', + ], + }, + ], + }, + }) + }) +}) diff --git a/yarn.lock b/yarn.lock index aedecc9995356..850e90f4f241b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -311,6 +311,11 @@ version "7.8.3" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" +"@babel/helper-plugin-utils@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + "@babel/helper-regex@^7.4.4": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" @@ -442,6 +447,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-dynamic-import" "^7.8.0" +"@babel/plugin-proposal-export-namespace-from@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" + integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-proposal-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" @@ -530,6 +543,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-flow@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" @@ -5571,19 +5591,19 @@ cssnano-preset-default@^4.0.7: postcss-svgo "^4.0.2" postcss-unique-selectors "^4.0.1" -cssnano-preset-simple@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-1.1.4.tgz#7b287a31df786348565d02342df71af8f758ac82" - integrity sha512-EYKDo65W+AxMViUijv/hvhbEnxUjmu3V7omcH1MatPOwjRLrAgVArUOE8wTUyc1ePFEtvV8oCT4/QSRJDorm/A== +cssnano-preset-simple@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-1.1.5.tgz#3a26829988ca20f5ffdb6d41c1df5b791db8a192" + integrity sha512-/zuE8EMVg7KFNR5Olj0ZnaMs3vtswcUcnr86zdVVCrhx3rY5DVDHWSiFE9/IGNl0SSVqi3AekPEnoNoLcQFHQw== dependencies: postcss "^7.0.32" -cssnano-simple@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-1.0.5.tgz#66ee528f3a4e60754e2625ea9f51ac315f5f0a92" - integrity sha512-NJjx2Er1C3pa75v1GwMKm0w6xAp1GsW2Ql1As4CWPNFxTgYFN5e8wblYeHfna13sANAhyIdSIPqKJjBO4CU5Eg== +cssnano-simple@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-1.0.6.tgz#e2e33c57b2b829a330467c7dbb15100bac37c8ea" + integrity sha512-q34pHOD8TFmZ6Etua7zJiebAl+8dV3Jb5O2pOdmCNJ/Ia8By9NQXk8at5WVW8qCVBFLm9ge5oaFXgU3FBFVTYw== dependencies: - cssnano-preset-simple "1.1.4" + cssnano-preset-simple "1.1.5" postcss "^7.0.32" cssnano-util-get-arguments@^4.0.0: