166 lines
5.5 KiB
JavaScript
166 lines
5.5 KiB
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')
|