mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Improved next/asset support (#3664)
* Allow next/asset to work properly with dynamic assetPrefix Now we use webpack's publicPath via client side. * Add test cases for dynamic assetPrefix and next/asset.
This commit is contained in:
parent
f046c0f6c2
commit
60cb06c1ba
|
@ -30,7 +30,10 @@ const {
|
|||
location
|
||||
} = window
|
||||
|
||||
// With this, static assets will work across zones
|
||||
// With dynamic assetPrefix it's no longer possible to set assetPrefix at the build time
|
||||
// So, this is how we do it in the client side at runtime
|
||||
__webpack_public_path__ = `${assetPrefix}/_next/webpack/` //eslint-disable-line
|
||||
// Initialize next/asset with the assetPrefix
|
||||
asset.setAssetPrefix(assetPrefix)
|
||||
|
||||
const asPath = getURL()
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
let assetPrefix
|
||||
|
||||
export default function asset (path) {
|
||||
// If the URL starts with http, we assume it's an
|
||||
if (/^https?:\/\//.test(path)) {
|
||||
return path
|
||||
}
|
||||
|
||||
const pathWithoutSlash = path.replace(/^\//, '')
|
||||
return `${assetPrefix}/static/${pathWithoutSlash}`
|
||||
}
|
||||
|
|
|
@ -126,7 +126,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
path: path.join(dir, config.distDir, isServer ? 'dist' : ''), // server compilation goes to `.next/dist`
|
||||
filename: '[name]',
|
||||
libraryTarget: 'commonjs2',
|
||||
publicPath: `${config.assetPrefix}/_next/webpack/`,
|
||||
// This saves chunks with the name given via require.ensure()
|
||||
chunkFilename: '[name]-[chunkhash].js',
|
||||
strictModuleExceptionHandling: true,
|
||||
|
|
10
test/integration/basic/pages/using-asset/asset.js
Normal file
10
test/integration/basic/pages/using-asset/asset.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import asset from 'next/asset'
|
||||
|
||||
export default () => (
|
||||
<div id='asset-page'>
|
||||
<img id='img1' src={asset('/the-image')} />
|
||||
<img id='img2' src={asset('the-image')} />
|
||||
<img id='img3' src={asset('http://the-image.com/the-image')} />
|
||||
<img id='img4' src={asset('https://the-image.com/the-image')} />
|
||||
</div>
|
||||
)
|
9
test/integration/basic/pages/using-asset/index.js
Normal file
9
test/integration/basic/pages/using-asset/index.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Link href='/using-asset/asset'>
|
||||
<a id='go-asset'>Asset</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
57
test/integration/basic/test/asset.js
Normal file
57
test/integration/basic/test/asset.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* global describe, it, expect */
|
||||
import cheerio from 'cheerio'
|
||||
import {
|
||||
renderViaHTTP
|
||||
} from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
export default (context) => {
|
||||
async function get$ (path) {
|
||||
const html = await renderViaHTTP(context.appPort, path)
|
||||
return cheerio.load(html)
|
||||
}
|
||||
|
||||
describe('With next/asset', () => {
|
||||
describe('with SSR', () => {
|
||||
it('should handle beginning slash properly', async () => {
|
||||
const $ = await get$('/using-asset/asset')
|
||||
expect($('#img1').attr('src')).toBe('/static/the-image')
|
||||
expect($('#img2').attr('src')).toBe('/static/the-image')
|
||||
})
|
||||
|
||||
it('should handle http(s) properly', async () => {
|
||||
const $ = await get$('/using-asset/asset')
|
||||
expect($('#img3').attr('src')).toBe('http://the-image.com/the-image')
|
||||
expect($('#img4').attr('src')).toBe('https://the-image.com/the-image')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with client navigation', () => {
|
||||
it('should handle beginning slash properly', async () => {
|
||||
const browser = await webdriver(context.appPort, '/using-asset')
|
||||
await browser
|
||||
.elementByCss('#go-asset').click()
|
||||
.waitForElementByCss('#asset-page')
|
||||
|
||||
expect(await browser.elementByCss('#img1').getAttribute('src'))
|
||||
.toBe(`http://localhost:${context.appPort}/static/the-image`)
|
||||
expect(await browser.elementByCss('#img2').getAttribute('src'))
|
||||
.toBe(`http://localhost:${context.appPort}/static/the-image`)
|
||||
browser.close()
|
||||
})
|
||||
|
||||
it('should handle http(s) properly', async () => {
|
||||
const browser = await webdriver(context.appPort, '/using-asset')
|
||||
await browser
|
||||
.elementByCss('#go-asset').click()
|
||||
.waitForElementByCss('#asset-page')
|
||||
|
||||
expect(await browser.elementByCss('#img3').getAttribute('src'))
|
||||
.toBe('http://the-image.com/the-image')
|
||||
expect(await browser.elementByCss('#img4').getAttribute('src'))
|
||||
.toBe('https://the-image.com/the-image')
|
||||
browser.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
|
@ -14,6 +14,7 @@ import rendering from './rendering'
|
|||
import clientNavigation from './client-navigation'
|
||||
import hmr from './hmr'
|
||||
import dynamic from './dynamic'
|
||||
import asset from './asset'
|
||||
|
||||
const context = {}
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||
|
@ -60,4 +61,5 @@ describe('Basic Features', () => {
|
|||
clientNavigation(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
dynamic(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
asset(context)
|
||||
})
|
||||
|
|
7
test/integration/custom-server/pages/asset.js
Normal file
7
test/integration/custom-server/pages/asset.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import asset from 'next/asset'
|
||||
|
||||
export default () => (
|
||||
<div id='asset-page'>
|
||||
<img src={asset('/myimage.png')} />
|
||||
</div>
|
||||
)
|
|
@ -1,3 +1,9 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default () => (
|
||||
<div>My Homepage</div>
|
||||
<div>
|
||||
<Link href='/asset'>
|
||||
<a id='go-asset'>Asset</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ const handleNextRequests = app.getRequestHandler()
|
|||
app.prepare().then(() => {
|
||||
const server = micro((req, res) => {
|
||||
if (/setAssetPrefix/.test(req.url)) {
|
||||
app.setAssetPrefix('https://cdn.com/myapp')
|
||||
app.setAssetPrefix(`http://127.0.0.1:${port}`)
|
||||
} else {
|
||||
// This is to support multi-zones support in localhost
|
||||
// and may be in staging deployments
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
import { join } from 'path'
|
||||
import getPort from 'get-port'
|
||||
import clone from 'clone'
|
||||
import cheerio from 'cheerio'
|
||||
import {
|
||||
initNextServerScript,
|
||||
killApp,
|
||||
renderViaHTTP
|
||||
} from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
let appPort
|
||||
|
@ -29,23 +31,51 @@ describe('Custom Server', () => {
|
|||
|
||||
describe('with dynamic assetPrefix', () => {
|
||||
it('should set the assetPrefix dynamically', async () => {
|
||||
const normalUsage = await renderViaHTTP(appPort, '/')
|
||||
expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)
|
||||
const normalUsage = await renderViaHTTP(appPort, '/asset')
|
||||
expect(normalUsage).not.toMatch(/127\.0\.0\.1/)
|
||||
|
||||
const dynamicUsage = await renderViaHTTP(appPort, '/?setAssetPrefix=1')
|
||||
expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
|
||||
const dynamicUsage = await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
|
||||
expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
|
||||
})
|
||||
|
||||
it('should set the assetPrefix to a given request', async () => {
|
||||
for (let lc = 0; lc < 1000; lc++) {
|
||||
const [normalUsage, dynamicUsage] = await Promise.all([
|
||||
await renderViaHTTP(appPort, '/'),
|
||||
await renderViaHTTP(appPort, '/?setAssetPrefix=1')
|
||||
await renderViaHTTP(appPort, '/asset'),
|
||||
await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
|
||||
])
|
||||
|
||||
expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)
|
||||
expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
|
||||
expect(normalUsage).not.toMatch(/127\.0\.0\.1/)
|
||||
expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
|
||||
}
|
||||
})
|
||||
|
||||
it('should support next/asset in server side', async () => {
|
||||
const $normal = cheerio.load(await renderViaHTTP(appPort, '/asset'))
|
||||
expect($normal('img').attr('src')).toBe('/static/myimage.png')
|
||||
|
||||
const $dynamic = cheerio.load(await renderViaHTTP(appPort, '/asset?setAssetPrefix=1'))
|
||||
expect($dynamic('img').attr('src')).toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
|
||||
})
|
||||
|
||||
it('should support next/asset in client side', async() => {
|
||||
const browser = await webdriver(context.appPort, '/')
|
||||
await browser
|
||||
.elementByCss('#go-asset').click()
|
||||
.waitForElementByCss('#asset-page')
|
||||
|
||||
expect(await browser.elementByCss('img').getAttribute('src'))
|
||||
.toBe(`http://localhost:${context.appPort}/static/myimage.png`)
|
||||
browser.close()
|
||||
|
||||
const browser2 = await webdriver(context.appPort, '/?setAssetPrefix=1')
|
||||
await browser2
|
||||
.elementByCss('#go-asset').click()
|
||||
.waitForElementByCss('#asset-page')
|
||||
|
||||
expect(await browser2.elementByCss('img').getAttribute('src'))
|
||||
.toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
|
||||
browser2.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue