Skip to content

Commit 9593c0e

Browse files
romansphaoqunjiang
authored andcommitted
feat(build): add --inline-vue flag to optionally disable externalization of Vue (#4261)
Resolves #4055. (cherry picked from commit 86f4f5f)
1 parent e79133b commit 9593c0e

File tree

10 files changed

+149
-10
lines changed

10 files changed

+149
-10
lines changed

docs/guide/build-targets.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ App is the default build target. In this mode:
1515

1616
::: tip Note on Vue Dependency
1717
In lib mode, Vue is *externalized*. This means the bundle will not bundle Vue even if your code imports Vue. If the lib is used via a bundler, it will attempt to load Vue as a dependency through the bundler; otherwise, it falls back to a global `Vue` variable.
18+
19+
To avoid this behavior provide `--inline-vue` flag to `build` command.
20+
21+
```
22+
vue-cli-service build --target lib --inline-vue
23+
```
1824
:::
1925

2026
You can build a single entry as a library using
@@ -68,6 +74,12 @@ Web Component mode does not support IE11 and below. [More details](https://githu
6874

6975
::: tip Note on Vue Dependency
7076
In web component mode, Vue is *externalized.* This means the bundle will not bundle Vue even if your code imports Vue. The bundle will assume `Vue` is available on the host page as a global variable.
77+
78+
To avoid this behavior provide `--inline-vue` flag to `build` command.
79+
80+
```
81+
vue-cli-service build --target wc --inline-vue
82+
```
7183
:::
7284

7385
You can build a single entry as a web component using

docs/guide/cli-service.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Options:
7575
--modern build app targeting modern browsers with auto fallback
7676
--target app | lib | wc | wc-async (default: app)
7777
--formats list of output formats for library builds (default: commonjs,umd,umd-min)
78+
--inline-vue include the Vue module in the final bundle of library or web component target
7879
--name name for lib or web-component mode (default: "name" in package.json or entry filename)
7980
--no-clean do not remove the dist directory before building the project
8081
--report generate report.html to help analyze bundle content

docs/ru/guide/build-targets.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919

2020
::: tip Примечание о зависимости Vue
2121
В режиме библиотеки Vue *экстернализируется*. Это означает, что сборка не будет содержать Vue, даже если ваш код его импортирует. Если библиотека используется через сборщик, он должен попытаться загрузить Vue в качестве зависимости через сборщик; в противном случае, он должен вернуться к глобальной переменной `Vue`.
22+
23+
Чтобы избежать экстернализиции Vue установите флаг `--inline-vue` для команды `build`.
24+
25+
```
26+
vue-cli-service build --target lib --inline-vue
27+
```
2228
:::
2329

2430
Вы можете запустить сборку одной точки входа в качестве библиотеки с помощью:
@@ -72,6 +78,12 @@ module.exports = {
7278

7379
::: tip Примечание зависимости Vue
7480
В режиме веб-компонентов Vue *экстернализируется.* Это означает, что сборка не будет содержать Vue, даже если ваш код его импортирует. Сборка будет подразумевать, что `Vue` доступен на странице в качестве глобальной переменной.
81+
82+
Чтобы избежать экстернализиции Vue установите флаг `--inline-vue` для команды `build`.
83+
84+
```
85+
vue-cli-service build --target wc --inline-vue
86+
```
7587
:::
7688

7789
Вы можете запустить сборку одной точки входа в качестве веб-компонента с помощью:

docs/ru/guide/cli-service.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ npx vue-cli-service serve
6767
--dest определить каталог сборки (по умолчанию: dist)
6868
--modern собирать приложение для современных браузеров с авто-фоллбэком для старых
6969
--target app | lib | wc | wc-async (по умолчанию: app)
70+
--inline-vue включить Vue в содержимое сборки библиотеки или веб-компонента
7071
--name имя библиотеки или режим веб-компонента (по умолчанию: "name" в package.json или имя файла точки входа)
7172
--no-clean не удалять каталог dist перед сборкой проекта
7273
--report сгенерировать report.html для анализа содержимого сборки

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,59 @@ test('build as lib with --filename option', async () => {
174174
return window.testLib.bar
175175
})).toBe(2)
176176
})
177+
178+
test('build as lib with --inline-vue', async () => {
179+
const project = await create('build-lib-inline-vue', defaultPreset)
180+
181+
await project.write('src/main-lib.js', `
182+
import Vue from 'vue'
183+
import App from "./components/App.vue"
184+
185+
document.addEventListener("DOMContentLoaded", function() {
186+
new Vue({
187+
render: h => h(App),
188+
}).$mount('body');
189+
});
190+
`)
191+
192+
await project.write('src/components/App.vue', `
193+
<template>
194+
<div>{{ message }}<div>
195+
</template>
196+
<script>
197+
export default {
198+
data() {
199+
return {
200+
message: 'Hello from Lib'
201+
}
202+
},
203+
}
204+
</script>
205+
`)
206+
207+
const { stdout } = await project.run('vue-cli-service build --target lib --inline-vue --name testLib src/main-lib.js')
208+
expect(stdout).toMatch('Build complete.')
209+
210+
expect(project.has('dist/demo.html')).toBe(true)
211+
expect(project.has('dist/testLib.common.js')).toBe(true)
212+
expect(project.has('dist/testLib.umd.js')).toBe(true)
213+
expect(project.has('dist/testLib.umd.min.js')).toBe(true)
214+
215+
const port = await portfinder.getPortPromise()
216+
server = createServer({ root: path.join(project.dir, 'dist') })
217+
218+
await new Promise((resolve, reject) => {
219+
server.listen(port, err => {
220+
if (err) return reject(err)
221+
resolve()
222+
})
223+
})
224+
225+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
226+
browser = launched.browser
227+
page = launched.page
228+
const divText = await page.evaluate(() => {
229+
return document.querySelector('div').textContent
230+
})
231+
expect(divText).toMatch('Hello from Lib')
232+
})

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,61 @@ test('build as single wc', async () => {
8989
expect(h1Text).toMatch('Welcome to Your Vue.js App')
9090
})
9191

92+
test('build as wc with --inline-vue', async () => {
93+
const project = await create('build-wc-inline-vue', defaultPreset)
94+
95+
await project.write('src/main-wc.js', `
96+
import Vue from 'vue'
97+
import App from "./components/App.vue"
98+
99+
document.addEventListener("DOMContentLoaded", function() {
100+
new Vue({
101+
render: h => h(App),
102+
}).$mount('body');
103+
});
104+
`)
105+
106+
await project.write('src/components/App.vue', `
107+
<template>
108+
<div>{{ message }}<div>
109+
</template>
110+
<script>
111+
export default {
112+
data() {
113+
return {
114+
message: 'Hello from Wc'
115+
}
116+
},
117+
}
118+
</script>
119+
`)
120+
121+
const { stdout } = await project.run('vue-cli-service build --target wc --inline-vue --name single-wc src/main-wc.js')
122+
expect(stdout).toMatch('Build complete.')
123+
124+
expect(project.has('dist/demo.html')).toBe(true)
125+
expect(project.has('dist/single-wc.js')).toBe(true)
126+
expect(project.has('dist/single-wc.min.js')).toBe(true)
127+
128+
const port = await portfinder.getPortPromise()
129+
server = createServer({ root: path.join(project.dir, 'dist') })
130+
131+
await new Promise((resolve, reject) => {
132+
server.listen(port, err => {
133+
if (err) return reject(err)
134+
resolve()
135+
})
136+
})
137+
138+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
139+
browser = launched.browser
140+
page = launched.page
141+
const divText = await page.evaluate(() => {
142+
return document.querySelector('div').textContent
143+
})
144+
expect(divText).toMatch('Hello from Wc')
145+
})
146+
92147
afterEach(async () => {
93148
if (browser) {
94149
await browser.close()

packages/@vue/cli-service/bin/vue-cli-service.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const args = require('minimist')(rawArgv, {
2222
'modern',
2323
'report',
2424
'report-json',
25+
'inline-vue',
2526
'watch',
2627
// serve
2728
'open',

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = (api, options) => {
2929
'--modern': `build app targeting modern browsers with auto fallback`,
3030
'--no-unsafe-inline': `build app without introducing inline scripts`,
3131
'--target': `app | lib | wc | wc-async (default: ${defaults.target})`,
32+
'--inline-vue': 'include the Vue module in the final bundle of library or web component target',
3233
'--formats': `list of output formats for library builds (default: ${defaults.formats})`,
3334
'--name': `name for lib or web-component mode (default: "name" in package.json or entry filename)`,
3435
'--filename': `file name for output, only usable for 'lib' target (default: value of --name)`,

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const fs = require('fs')
22
const path = require('path')
33

4-
module.exports = (api, { entry, name, formats, filename }, options) => {
4+
module.exports = (api, { entry, name, formats, filename, 'inline-vue': inlineVue }, options) => {
55
const { log, error } = require('@vue/cli-shared-utils')
66
const abort = msg => {
77
log()
@@ -94,11 +94,13 @@ module.exports = (api, { entry, name, formats, filename }, options) => {
9494
rawConfig.externals = [
9595
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
9696
{
97-
vue: {
98-
commonjs: 'vue',
99-
commonjs2: 'vue',
100-
root: 'Vue'
101-
}
97+
...(inlineVue || {
98+
vue: {
99+
commonjs: 'vue',
100+
commonjs2: 'vue',
101+
root: 'Vue'
102+
}
103+
})
102104
}
103105
].filter(Boolean)
104106

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const path = require('path')
22
const { resolveEntry, fileToComponentName } = require('./resolveWcEntry')
33

4-
module.exports = (api, { target, entry, name }) => {
4+
module.exports = (api, { target, entry, name, 'inline-vue': inlineVue }) => {
55
// Disable CSS extraction and turn on CSS shadow mode for vue-style-loader
66
process.env.VUE_CLI_CSS_SHADOW_MODE = true
77

@@ -100,9 +100,7 @@ module.exports = (api, { target, entry, name }) => {
100100
// externalize Vue in case user imports it
101101
rawConfig.externals = [
102102
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
103-
{
104-
vue: 'Vue'
105-
}
103+
{ ...(inlineVue || { vue: 'Vue' }) }
106104
].filter(Boolean)
107105

108106
const entryName = `${libName}${minify ? `.min` : ``}`

0 commit comments

Comments
 (0)