Skip to content

Commit 9aaf32f

Browse files
pimlietmorehouse
authored andcommitted
feat(nuxt-module): add tree-shaking support to Nuxt module (#2654)
1 parent afbb650 commit 9aaf32f

File tree

3 files changed

+104
-44
lines changed

3 files changed

+104
-44
lines changed

docs/markdown/intro/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,30 @@ In your app main entry point include the single custom SCSS file (when using `sa
114114
import 'custom.scss'
115115
```
116116

117+
### Tree shaking with Nuxt.js
118+
119+
If you wish to reduce your bundle size because you only use a subset of the available
120+
BootstrapVue plugins, you can configure the list of BootstrapVue
121+
`componentPlugins` or `directivePlugins` you want to globally install in
122+
your Nuxt.js project.
123+
124+
```js
125+
{
126+
modules: ['bootstrap-vue/nuxt'],
127+
bootstrapVue: {
128+
componentPlugins: [
129+
'Form',
130+
'FormCheckbox',
131+
'FormInput',
132+
'FormRadio'
133+
],
134+
directivePlugins: [
135+
'Popover'
136+
]
137+
}
138+
}
139+
```
140+
117141
## Vue CLI 2
118142

119143
BootstrapVue has two Vue CLI templates available:

nuxt/index.js

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,78 @@
11
const { resolve } = require('path')
22

3-
function pickFirst(...args) {
4-
for (const arg of args) {
5-
if (arg !== undefined) {
6-
return arg
3+
module.exports = function nuxtBootstrapVue(moduleOptions = {}) {
4+
this.nuxt.hook('build:before', () => {
5+
function pickFirst(...args) {
6+
for (const arg of args) {
7+
if (arg !== undefined) {
8+
return arg
9+
}
10+
}
711
}
8-
}
9-
}
1012

11-
module.exports = function nuxtBootstrapVue(moduleOptions = {}) {
12-
// Merge moduleOptions with default
13-
const options = {
14-
...this.options.bootstrapVue,
15-
...moduleOptions
16-
}
17-
18-
const bootstrapVueCSS = pickFirst(
19-
options.bootstrapVueCSS,
20-
options.bootstrapVueCss,
21-
options.bvCSS,
22-
// Defaults to `true` if no other options provided
23-
true
24-
)
25-
if (bootstrapVueCSS) {
26-
// Add BootstrapVue CSS
27-
this.options.css.unshift('bootstrap-vue/dist/bootstrap-vue.css')
28-
}
29-
30-
const bootstrapCSS = pickFirst(
31-
options.bootstrapCSS,
32-
options.bootstrapCss,
33-
options.css,
34-
// Defaults to `true` if no other options provided
35-
true
36-
)
37-
if (bootstrapCSS) {
38-
// Add Bootstrap CSS before BootstrapVue CSS
39-
this.options.css.unshift('bootstrap/dist/css/bootstrap.css')
40-
}
41-
42-
// Transpile src
43-
this.options.build.transpile.push('bootstrap-vue/src')
44-
45-
// Register plugin, pasing options to plugin template
46-
this.addPlugin({
47-
src: resolve(__dirname, 'plugin.template.js'),
48-
fileName: 'bootstrap-vue.js'
13+
const kebabCase = str =>
14+
str.replace(
15+
/([_\s]+([a-zA-Z])|([A-Z]))/g,
16+
(m, $1, $2, $3, o) => (o ? '-' : '') + ($2 || $3 || '').toLowerCase()
17+
)
18+
const pascalCase = str => str.replace(/(^|[-_\s]+)(.)/g, (m, $1, $2) => $2.toUpperCase())
19+
20+
// Merge moduleOptions with default
21+
const options = {
22+
...this.options.bootstrapVue,
23+
...moduleOptions
24+
}
25+
26+
const bootstrapVueCSS = pickFirst(
27+
options.bootstrapVueCSS,
28+
options.bootstrapVueCss,
29+
options.bvCSS,
30+
// Defaults to `true` if no other options provided
31+
true
32+
)
33+
if (bootstrapVueCSS) {
34+
// Add BootstrapVue CSS
35+
this.options.css.unshift('bootstrap-vue/dist/bootstrap-vue.css')
36+
}
37+
38+
const bootstrapCSS = pickFirst(
39+
options.bootstrapCSS,
40+
options.bootstrapCss,
41+
options.css,
42+
// Defaults to `true` if no other options provided
43+
true
44+
)
45+
if (bootstrapCSS) {
46+
// Add Bootstrap CSS
47+
this.options.css.unshift('bootstrap/dist/css/bootstrap.css')
48+
}
49+
50+
// Transpile src
51+
this.options.build.transpile.push('bootstrap-vue/src')
52+
53+
const templateOptions = {}
54+
55+
// TODO: also add support for individual components & directives
56+
for (const type of ['componentPlugins', 'directivePlugins']) {
57+
const bvPlugins = Array.isArray(options[type]) ? options[type] : []
58+
59+
templateOptions[type] = bvPlugins
60+
// convert everything to kebab
61+
.map(p => kebabCase(p))
62+
// remove duplicate items
63+
.filter((p, i, arr) => arr.indexOf(p) === i)
64+
.map(pluginDir => {
65+
const moduleName = (type === 'directivePlugins' ? 'v' : '') + pascalCase(pluginDir)
66+
return [moduleName, pluginDir]
67+
})
68+
}
69+
70+
// Register plugin, pasing options to plugin template
71+
this.addPlugin({
72+
src: resolve(__dirname, 'plugin.template.js'),
73+
fileName: 'bootstrap-vue.js',
74+
options: templateOptions
75+
})
4976
})
5077
}
5178

nuxt/plugin.template.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
import Vue from 'vue'
2+
<% if (options.componentPlugins.length || options.directivePlugins.length) { %><%=
3+
options.componentPlugins.reduce((acc, p) => (acc += `import ${p[0]} from 'bootstrap-vue/es/components/${p[1]}'\n` ), '') %><%=
4+
options.directivePlugins.reduce((acc, p) => (acc += `import ${p[0]} from 'bootstrap-vue/es/directives/${p[1]}'\n` ), '') %>
5+
6+
<%=
7+
options.componentPlugins.reduce((acc, p) => (acc += `Vue.use(${p[0]})\n` ), '') %><%=
8+
options.directivePlugins.reduce((acc, p) => (acc += `Vue.use(${p[0]})\n` ), '') %>
9+
<% } else { %>
210
import BootstrapVue from 'bootstrap-vue/es'
311

412
Vue.use(BootstrapVue)
13+
<% } %>

0 commit comments

Comments
 (0)