bootstrap-vue
Version:
BootstrapVue, with over 40 plugins and more than 75 custom components, provides one of the most comprehensive implementations of Bootstrap v4 components and grid system for Vue.js. With extensive and automated WAI-ARIA accessibility markup.
166 lines (143 loc) • 5.64 kB
JavaScript
const { resolve } = require('path')
// --- Utility methods ---
const pickFirst = (...args) => {
for (const arg of args) {
if (arg !== undefined) {
return arg
}
}
}
// Converts a kebab-case or camelCase string to PascalCase
const unKebabRE = /-(\w)/g
const pascalCase = str => {
str = str.replace(unKebabRE, (_, c) => (c ? c.toUpperCase() : ''))
return str.charAt(0).toUpperCase() + str.slice(1)
}
// --- Constants ---
// Path to index file when using bootstrap-vue source code
const srcIndex = 'bootstrap-vue/src/index.js'
// --- Main Nuxt module ---
module.exports = function nuxtBootstrapVue(moduleOptions = {}) {
this.nuxt.hook('build:before', () => {
// Merge moduleOptions with default
const options = {
...this.options.bootstrapVue,
...moduleOptions
}
// Ensure we have arrays
this.options.css = [].concat(this.options.css || [])
this.options.build.transpile = [].concat(this.options.build.transpile || [])
const bootstrapVueCSS = pickFirst(
options.bootstrapVueCSS,
options.bootstrapVueCss,
options.bvCSS,
// Defaults to `true` if no other options provided
true
)
if (bootstrapVueCSS) {
// Add BootstrapVue CSS
this.options.css.unshift('bootstrap-vue/dist/bootstrap-vue.css')
}
const bootstrapCSS = pickFirst(
options.bootstrapCSS,
options.bootstrapCss,
options.css,
// Defaults to `true` if no other options provided
true
)
if (bootstrapCSS) {
// Add Bootstrap CSS
this.options.css.unshift('bootstrap/dist/css/bootstrap.css')
}
// Component src prop resolving
this.options.build.loaders.vue.transformAssetUrls = {
// Nuxt default is missing `poster` for video
video: ['src', 'poster'],
// Nuxt default is missing image
image: 'xlink:href',
// Add BootstrapVue specific component asset items
'b-img': 'src',
'b-img-lazy': ['src', 'blank-src'],
'b-card': 'img-src',
'b-card-img': 'src',
'b-card-img-lazy': ['src', 'blank-src'],
'b-carousel-slide': 'img-src',
'b-embed': 'src',
// Ensure super supplied values/overrides are not lost
...this.options.build.loaders.vue.transformAssetUrls
}
// Enable transpilation of src/ directory
this.options.build.transpile.push('bootstrap-vue/src')
// Use pre-tranpiled or src/
const usePretranspiled = pickFirst(options.usePretranspiled, this.options.dev, false)
if (!usePretranspiled) {
// Use bootstrap-vue source code for smaller prod builds
// by aliasing 'bootstrap-vue' to the source files.
this.extendBuild((config, { isServer }) => {
if (!config.resolve.alias) {
config.resolve.alias = {}
}
const index = require.resolve(srcIndex)
const srcDir = index.replace(/index\.js$/, '')
// We prepend a $ to ensure that it is only used for
// `import from 'bootstrap-vue'` not `import from 'bootstrap-vue/*'`
config.resolve.alias['bootstrap-vue$'] = index
// If users are still cherry-picking modules from esm/ or es/ (legacy),
// alias them to src/ to prevent duplicate code imports
config.resolve.alias['bootstrap-vue/esm/'] = srcDir
config.resolve.alias['bootstrap-vue/es/'] = srcDir
})
}
// Base options available to template
const templateOptions = {
// Flag if we are tree shaking
treeShake: false
}
// Specific component and/or directive plugins
for (const type of ['componentPlugins', 'directivePlugins']) {
const bvPlugins = Array.isArray(options[type]) ? options[type] : []
templateOptions[type] = bvPlugins
// Normalize plugin name to `${Name}Plugin` (component) or `VB${Name}Plugin` (directive)
// Required for backwards compatability with old plugin import names
.map(plugin => {
// Ensure PascalCase name
plugin = pascalCase(plugin)
// Ensure new naming convention for directive plugins prefixed with `VB`
plugin = type === 'directivePlugins' && !/^VB/.test(plugin) ? `VB${plugin}` : plugin
// Ensure prefixed with `Plugin`
plugin = /Plugin$/.test(plugin) ? plugin : `${plugin}Plugin`
return plugin
})
// Remove duplicate items
.filter((plugin, i, arr) => arr.indexOf(plugin) === i)
if (templateOptions[type].length > 0) {
templateOptions.treeShake = true
}
}
// Specific components and/or directives
for (const type of ['components', 'directives']) {
const ComponentsOrDirectives = Array.isArray(options[type]) ? options[type] : []
templateOptions[type] = ComponentsOrDirectives
// Ensure PascalCase name
.map(item => pascalCase(item))
// Ensure prefixed with `V`
.map(item => (type === 'directives' && !/^V/.test(item) ? `V${item}` : item))
// Remove duplicate items
.filter((item, i, arr) => arr.indexOf(item) === i)
if (templateOptions[type].length > 0) {
templateOptions.treeShake = true
}
}
// Add BootstrapVue configuration if present
if (options.config && Object.prototype.toString.call(options.config) === '[object Object]') {
templateOptions.config = { ...options.config }
}
// Register plugin, passing options to plugin template
this.addPlugin({
src: resolve(__dirname, 'plugin.template.js'),
fileName: 'bootstrap-vue.js',
options: templateOptions
})
})
}
module.exports.meta = require('../package.json')