Last active
May 6, 2021 22:56
-
-
Save renoirb/7305b8c767496934dc707525aa514b74 to your computer and use it in GitHub Desktop.
Vue Component Library Build
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Related to https://github.com/chrisvfritz/hello-vue-components/tree/v1.2.3/build-utils | |
// New file: build-utils/index.js | |
const fs = require('fs') | |
const { env, cwd } = process | |
const workspacePath = __dirname.substring(0, __dirname.length - 6) | |
const workspacePackagePath = Reflect.has(env, 'PWD') ? env.PWD : cwd() | |
function packageSlugOrExit(fileName) { | |
const filePath = workspacePackagePath + '/' + fileName | |
const moduleSlug = workspacePackagePath.substring(__dirname.length - 5) // Build is 5 characters offset from what we want. | |
// workspacePackagePath : /mnt/c/Users/renoir.boulanger/workspaces/context-frontend/frontend-bindings/repo/packages/vue-components-value | |
// __dirname : /mnt/c/Users/renoir.boulanger/workspaces/context-frontend/frontend-bindings/repo/build | |
// moduleSlug : packages/vue-components-value | |
let fileExists = false | |
try { | |
// https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback | |
const check = fs.accessSync(filePath, fs.constants.F_OK) | |
fileExists = check === undefined | |
} catch (e) { | |
const message = `Script cannot be run for this package, packageSlugOrExit(${fileName}) failed; | |
${e.message} | |
` | |
console.error(message) | |
process.exit(1) | |
} | |
return fileExists ? moduleSlug : fileExists | |
} | |
module.exports = { | |
packageSlugOrExit, | |
workspacePath, | |
workspacePackagePath, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Vue Components Build Helpers: Get Components' library component names. | |
* | |
* Source: https://github.com/chrisvfritz/hello-vue-components/blob/v1.2.3/build-utils/update-index-file.js | |
*/ | |
const fs = require('fs') | |
const path = require('path') | |
const componentNames = require('./component-names') | |
const { packageSlugOrExit, workspacePackagePath } = require('.') | |
// packageSlugOrExit: Provided the file exists for this package, or exit | |
packageSlugOrExit('vue.config.js') | |
const libraryIndexFile = path.resolve(workspacePackagePath, 'src/index.js') | |
console.log(`Packaging:`) | |
console.log(' path:', workspacePackagePath) | |
console.log(` components:\n `, componentNames) | |
const indexFileContent = `\ | |
/** | |
* A Vue Components Package | |
* | |
* THIS FILE IS AUTOMATICALLY GENERATED | |
* YOU SHOULD NEVER UPDATE THIS FILE DIRECTLY | |
* | |
* Refer to {@link https://gitlab.private.example.org:50043/ProjectName/vue-components-value.git} | |
* | |
* build-utils/update-index-file.js | |
*/ | |
${componentNames | |
.map(componentName => `import ${componentName} from './${componentName}'`) | |
.join('\n')} | |
// Export components individually | |
export const components = { ${componentNames.map(componentName => componentName).join(', ')} } | |
// What should happen if the user installs the library as a plugin | |
export function install(Vue) { | |
${componentNames | |
.map(componentName => ` Vue.component('${componentName}', ${componentName})`) | |
.join('\n')} | |
} | |
// Export the library as a plugin | |
const plugin = { install, components, } | |
export default plugin | |
` | |
fs.writeFileSync(libraryIndexFile, indexFileContent) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
src=$(shell ls src/*.vue) | |
out=$(subst src,dist,$(subst .vue,,$(src))) | |
ifndef OUTPUT | |
OUTPUT = lib | |
endif | |
all: dist/index.js $(out) | |
clean: | |
rm -rI dist/ | |
node_modules: | |
yarn | |
dist: node_modules | |
yarn build | |
# If we do not make the src/index.js .PHONY, it wont get regenerated | |
.PHONY: src/index.js | |
src/index.js: node_modules | |
$(info Updating src/index.js) | |
node build-utils/update-index-file.js.js | |
dist/index.js: src/index.js | |
$(info Creating a Library to dist/ OUTPUT=$(OUTPUT)) | |
ifeq "$(OUTPUT)" "lib" | |
node_modules/.bin/vue-cli-service build src/index.js --target lib --name index --dest dist/ | |
endif | |
ifeq "$(OUTPUT)" "wc" | |
node_modules/.bin/vue-cli-service build --target wc --name index 'src/*.vue' | |
endif | |
ifeq "$(OUTPUT)" "wc-async" | |
node_modules/.bin/vue-cli-service build --target wc-async --name index 'src/*.vue' | |
endif | |
dist/%: src/index.js src/%.vue | |
$(info Creating a Vue Component for $<) | |
node_modules/.bin/vue-cli-service build $< --target lib --name index --dest $@/ |
Another script variant (scavenged not fully functional)
Components list
Say we have a components/
folder, where each child are UBadge.vue
so we want to know names and path.
{
"UBadge": "UBadge/UBadge",
"UBadgeStatus": "UBadge/UBadgeStatus",
"UCopyrightLinks": "UCopyrightLinks/UCopyrightLinks",
"UDataListLabelProp": "UDataList/UDataListLabelProp",
"UDataListTable": "UDataList/UDataListTable",
"UDataListVertical": "UDataList/UDataListVertical",
"UNavigationFooter": "UNavigationFooter/UNavigationFooter",
"UPageFooter": "UPageFooter/UPageFooter",
"UProgressBar": "UProgressBar/UProgressBar",
"UProse": "UProse/UProse",
"USelectiveMultiSelect": "USelective/USelectiveMultiSelect",
"UFilteringOperator": "UFiltering/UFilteringOperator",
"UValueBoolean": "UValue/UValueBoolean",
"UValueDate": "UValue/UValueDate",
"UValueLink": "UValue/UValueLink",
"UValueNumber": "UValue/UValueNumber",
"UValueTrinary": "UValue/UValueTrinary"
}
Generated entry point
We want the file in src/lib.js
to list all components automatically based on that list from src/components/list.json
//
// Component Library v1.0.1, Automatically generated by scripts/build/generate-lib.js
//
import '@/style/index.scss'
import UBadge from '@/components/UBadge/UBadge'
import UBadgeStatus from '@/components/UBadge/UBadgeStatus'
import UCopyrightLinks from '@/components/UCopyrightLinks/UCopyrightLinks'
import UDataListLabelProp from '@/components/UDataList/UDataListLabelProp'
import UDataListTable from '@/components/UDataList/UDataListTable'
import UDataListVertical from '@/components/UDataList/UDataListVertical'
import UNavigationFooter from '@/components/UNavigationFooter/UNavigationFooter'
import UPageFooter from '@/components/UPageFooter/UPageFooter'
import UProgressBar from '@/components/UProgressBar/UProgressBar'
import UProse from '@/components/UProse/UProse'
import USelectiveMultiSelect from '@/components/USelective/USelectiveMultiSelect'
import UFilteringOperator from '@/components/UFiltering/UFilteringOperator'
import UValueBoolean from '@/components/UValue/UValueBoolean'
import UValueDate from '@/components/UValue/UValueDate'
import UValueLink from '@/components/UValue/UValueLink'
import UValueNumber from '@/components/UValue/UValueNumber'
import UValueTrinary from '@/components/UValue/UValueTrinary'
const components = {
UBadge,
UBadgeStatus,
UCopyrightLinks,
UDataListLabelProp,
UDataListTable,
UDataListVertical,
UNavigationFooter,
UPageFooter,
UProgressBar,
UProse,
USelectiveMultiSelect,
UFilteringOperator,
UValueBoolean,
UValueDate,
UValueLink,
UValueNumber,
UValueTrinary,
}
const main = {
version: '1.0.1',
components: {
...components,
},
install (Vue, options = {}) {
for (const [
// eslint-disable-next-line
className,
component,
] of Object.entries(components)) {
Vue.component(component.name, component)
}
},
}
export default main
The "generate lib" script
here is a build script
/**
* Preparing vue-cli-service build and library entry point.
*
* Thanks to https://github.com/ElemeFE/element/blob/dev/build/bin/build-entry.js
*/
const fs = require('fs')
const path = require('path')
const _ = require('lodash')
const EOL = `\n` // require('os').EOL
const LIBRARY_ENTRY_FILE = path.join(__dirname, '../../src/lib.js')
// const LIBRARY_BUILD_SCRIPT_FILE = path.join(__dirname, '../../dist.sh')
const components = require('../../src/components/list.json')
const pkg = require('../../package.json')
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g
const relativizePath = somePath => path.relative(process.cwd(), somePath)
const render = (template, ...args) => {
const compiled = _.template(template)
return compiled(...args)
}
const asComment = (lines, type) => {
const prepend = {
'js': '//',
'sh': '##',
}
const isValidType = Object.keys(prepend).includes(type)
if (isValidType !== true) {
throw new Error(`Invalid comment type ${type}`)
}
return lines.map(i => prepend[type].concat(i)).join(EOL)
}
const GENERATED_BY = relativizePath(process.argv[1])
// const BUILD_TEMPLATE = 'node_modules/.bin/vue-cli-service build --target lib --mode production --name {{name}} --no-clean src/components/{{namespacedName}}.vue'
const IMPORT_TEMPLATE = 'import {{name}} from \'@/components/{{namespacedName}}\''
// ============================================================================
const FRONT_MATTER = [
'',
' Component Library v' + pkg.version + ', Automatically generated by ' + GENERATED_BY,
' Refer to ' + pkg.homepage,
'',
]
// eslint-disable-next-line
const BUILD_SCRIPT_TEMPLATE = `#!/usr/bin/env bash
` + asComment(FRONT_MATTER, 'sh') + `
{{buildScriptLines}}
echo 'Done!'
`
const ENTRY_FILE_TEMPLATE = asComment(FRONT_MATTER, 'js') + `
import '@/style/index.scss'
{{include}}
const components = {
{{install}},
}
const main = {
version: '{{version}}',
components: {
...components,
},
install (Vue, options = {}) {
for (const [
// eslint-disable-next-line
className,
component,
] of Object.entries(components)) {
Vue.component(component.name, component)
}
},
}
export default main
`
// ============================================================================
const includeComponentTemplate = []
const installTemplate = []
const listTemplate = []
// const buildScriptLines = []
Object.keys(components).forEach(name => {
const namespacedName = components[name]
// buildScriptLines.push(render(BUILD_TEMPLATE, {
// name,
// namespacedName,
// }))
includeComponentTemplate.push(render(IMPORT_TEMPLATE, {
name,
namespacedName,
}))
listTemplate.push(` ${name}`)
installTemplate.push(` ${name}`)
})
var renderedEntryFileContents = render(ENTRY_FILE_TEMPLATE, {
include: includeComponentTemplate.join(EOL),
list: listTemplate.join(',' + EOL),
install: installTemplate.join(',' + EOL),
version: process.env.VERSION || pkg.version,
homepage: pkg.homepage,
})
// var renderedBuildScriptFileContents = render(BUILD_SCRIPT_TEMPLATE, {
// buildScriptLines: buildScriptLines.join(EOL),
// })
fs.writeFileSync(LIBRARY_ENTRY_FILE, renderedEntryFileContents)
console.log('DONE:', relativizePath(LIBRARY_ENTRY_FILE))
// fs.writeFileSync(LIBRARY_BUILD_SCRIPT_FILE, renderedBuildScriptFileContents, {
// flag: 'w',
// })
// console.log('DONE:', relativizePath(LIBRARY_BUILD_SCRIPT_FILE))
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This Gist is related to the following Thread on Twitter