Skip to content

Commit

Permalink
Use deterministic names for dynamic import (vercel#2788)
Browse files Browse the repository at this point in the history
* Always use the same name for the same dynamic import.

* Add unit tests for the modulePath generation.

* Allow tests to run correctly on Windows.

* Make the chunk name a bit pretty.

* Fix tests to run on Windows.
  • Loading branch information
arunoda authored Aug 16, 2017
1 parent ed0c144 commit 68738d1
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
26 changes: 23 additions & 3 deletions server/build/babel/plugins/handle-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// We've added support for SSR with this version
import template from 'babel-template'
import syntax from 'babel-plugin-syntax-dynamic-import'
import UUID from 'uuid'
import { dirname, resolve, sep } from 'path'
import Crypto from 'crypto'

const TYPE_IMPORT = 'Import'

Expand Down Expand Up @@ -37,14 +38,33 @@ const buildImport = (args) => (template(`
)
`))

export function getModulePath (sourceFilename, moduleName) {
// resolve only if it's a local module
const modulePath = (moduleName[0] === '.')
? resolve(dirname(sourceFilename), moduleName) : moduleName

const cleanedModulePath = modulePath
.replace(/(index){0,1}\.js$/, '') // remove .js, index.js
.replace(/[/\\]$/, '') // remove end slash

return cleanedModulePath
}

export default () => ({
inherits: syntax,

visitor: {
CallExpression (path) {
CallExpression (path, state) {
if (path.node.callee.type === TYPE_IMPORT) {
const moduleName = path.node.arguments[0].value
const name = `${moduleName.replace(/[^\w]/g, '-')}-${UUID.v4()}`
const sourceFilename = state.file.opts.filename

const modulePath = getModulePath(sourceFilename, moduleName)
const modulePathHash = Crypto.createHash('md5').update(modulePath).digest('hex')

const relativeModulePath = modulePath.replace(`${process.cwd()}${sep}`, '')
const name = `${relativeModulePath.replace(/[^\w]/g, '-')}-${modulePathHash}`

const newImport = buildImport({
name
})({
Expand Down
42 changes: 42 additions & 0 deletions test/unit/handle-import-babel-plugin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* global describe, it, expect */
import { getModulePath } from '../../dist/server/build/babel/plugins/handle-import'

function cleanPath (mPath) {
return mPath
.replace(/\\/g, '/')
.replace(/^.*:/, '')
}

describe('handle-import-babel-plugin', () => {
describe('getModulePath', () => {
it('should not do anything to NPM modules', () => {
const mPath = getModulePath('/abc/pages/about.js', 'cool-module')
expect(mPath).toBe('cool-module')
})

it('should not do anything to private NPM modules', () => {
const mPath = getModulePath('/abc/pages/about.js', '@zeithq/cool-module')
expect(mPath).toBe('@zeithq/cool-module')
})

it('should resolve local modules', () => {
const mPath = getModulePath('/abc/pages/about.js', '../components/hello.js')
expect(cleanPath(mPath)).toBe('/abc/components/hello')
})

it('should remove index.js', () => {
const mPath = getModulePath('/abc/pages/about.js', '../components/c1/index.js')
expect(cleanPath(mPath)).toBe('/abc/components/c1')
})

it('should remove .js', () => {
const mPath = getModulePath('/abc/pages/about.js', '../components/bb.js')
expect(cleanPath(mPath)).toBe('/abc/components/bb')
})

it('should remove end slash', () => {
const mPath = getModulePath('/abc/pages/about.js', '../components/bb/')
expect(cleanPath(mPath)).toBe('/abc/components/bb')
})
})
})

0 comments on commit 68738d1

Please sign in to comment.