Skip to content

Commit 1dc47eb

Browse files
committed
feat(build): support named exports when building --target lib with js/ts entry
close #1436 BREAKING CHANGE: When building a js/ts entry file with --target lib, the library now exposes a Module with both default and named exports. This means in the UMD build, the default export now needs to be accessed as `window.yourLib.default`, and in the CommonJS build as `const yourLib = require('yourLib').default`. If you don't have named exports and want to retain the previous behavior, you can configure webpack to use `output.libraryExport: 'default'` in `vue.config.js`.
1 parent b832ff2 commit 1dc47eb

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

packages/@vue/cli-service/__tests__/buildLib.spec.js

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
jest.setTimeout(30000)
1+
jest.setTimeout(40000)
22

33
const path = require('path')
44
const portfinder = require('portfinder')
@@ -8,6 +8,12 @@ const create = require('@vue/cli-test-utils/createTestProject')
88
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
99

1010
let server, browser, page
11+
12+
afterEach(async () => {
13+
await browser.close()
14+
server.close()
15+
})
16+
1117
test('build as lib', async () => {
1218
const project = await create('build-lib', defaultPreset)
1319

@@ -45,7 +51,40 @@ test('build as lib', async () => {
4551
expect(h3Text).toMatch('Installed CLI Plugins')
4652
})
4753

48-
afterAll(async () => {
49-
await browser.close()
50-
server.close()
54+
test('build as lib (js)', async () => {
55+
const project = await create('build-lib-js', defaultPreset)
56+
await project.write('src/main.js', `
57+
export default { foo: 1 }
58+
export const bar = 2
59+
`)
60+
const { stdout } = await project.run('vue-cli-service build --target lib --name testLib src/main.js')
61+
expect(stdout).toMatch('Build complete.')
62+
63+
expect(project.has('dist/demo.html')).toBe(true)
64+
expect(project.has('dist/testLib.common.js')).toBe(true)
65+
expect(project.has('dist/testLib.umd.js')).toBe(true)
66+
expect(project.has('dist/testLib.umd.min.js')).toBe(true)
67+
68+
const port = await portfinder.getPortPromise()
69+
server = createServer({ root: path.join(project.dir, 'dist') })
70+
71+
await new Promise((resolve, reject) => {
72+
server.listen(port, err => {
73+
if (err) return reject(err)
74+
resolve()
75+
})
76+
})
77+
78+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
79+
browser = launched.browser
80+
page = launched.page
81+
82+
// should expose a module with default and named exports
83+
expect(await page.evaluate(() => {
84+
return window.testLib.default.foo
85+
})).toBe(1)
86+
87+
expect(await page.evaluate(() => {
88+
return window.testLib.bar
89+
})).toBe(2)
5190
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<title><%- htmlWebpackPlugin.options.libName %> demo</title>
2+
<script src="./<%- htmlWebpackPlugin.options.libName %>.umd.js"></script>
3+
<link rel="stylesheet" href="./<%- htmlWebpackPlugin.options.libName %>.css">
4+
5+
<script>
6+
console.log(<%- htmlWebpackPlugin.options.libName %>)
7+
</script>

packages/@vue/cli-service/lib/commands/build/resolveLibConfig.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module.exports = (api, { entry, name }, options) => {
2121
)
2222
}
2323

24+
const isVueEntry = /\.vue$/.test(entry)
2425
const libName = (
2526
name ||
2627
api.service.pkg.name ||
@@ -57,10 +58,11 @@ module.exports = (api, { entry, name }, options) => {
5758

5859
// inject demo page for umd
5960
if (genHTML) {
61+
const template = isVueEntry ? 'demo-lib.html' : 'demo-lib-js.html'
6062
config
6163
.plugin('demo-html')
6264
.use(require('html-webpack-plugin'), [{
63-
template: path.resolve(__dirname, './demo-lib.html'),
65+
template: path.resolve(__dirname, template),
6466
inject: false,
6567
filename: 'demo.html',
6668
libName
@@ -80,21 +82,22 @@ module.exports = (api, { entry, name }, options) => {
8082
[entryName]: require.resolve('./entry-lib.js')
8183
}
8284

83-
Object.assign(rawConfig.output, {
84-
filename: `${entryName}.js`,
85-
chunkFilename: `${entryName}.[name].js`,
85+
rawConfig.output = Object.assign({
8686
library: libName,
87-
libraryExport: 'default',
87+
libraryExport: isVueEntry ? 'default' : undefined,
8888
libraryTarget: format,
89-
// use dynamic publicPath so this can be deployed anywhere
90-
// the actual path will be determined at runtime by checking
91-
// document.currentScript.src.
92-
publicPath: '',
9389
// preserve UDM header from webpack 3 until webpack provides either
9490
// libraryTarget: 'esm' or target: 'universal'
9591
// https://github.com/webpack/webpack/issues/6522
9692
// https://github.com/webpack/webpack/issues/6525
9793
globalObject: `typeof self !== 'undefined' ? self : this`
94+
}, rawConfig.output, {
95+
filename: `${entryName}.js`,
96+
chunkFilename: `${entryName}.[name].js`,
97+
// use dynamic publicPath so this can be deployed anywhere
98+
// the actual path will be determined at runtime by checking
99+
// document.currentScript.src.
100+
publicPath: ''
98101
})
99102

100103
return rawConfig

0 commit comments

Comments
 (0)