UNPKG

vue-build-helper

Version:

Streamline the Vue CLI 3 build process

191 lines (175 loc) 7.61 kB
const path = require('path') const FileHound = require('filehound') const { upperCamelCase } = require('../common/case-helpers') const { deleteFile, directoryExists } = require('../common/fs-helpers') const defaultDestPath = path.join(process.cwd(), 'dist') // TODO move to shared module const filterOn = 'common.js' // Enable or disable debug output let debug = false // Enable or disable verbose output let verbose = false // Enable or disable quiet mode let quiet = false /** * Correct the path separator on Windows from backslash to forward slash. * @param {string} filePath - Fully qualified path of the file to correct the path for * @returns {string} */ function correctPathSeparator (filePath) { return filePath.replace(/\\/g, '/') } /** * Custom filter to filter files by (*.common.js). * @param {Object} file - The file object * @returns {boolean} true if the file meets the filter, otherwise false */ // TODO move to shared module function customFilter (file) { return file._pathname.endsWith(filterOn) > 0 } /** * Remove the filter (*.common.js) from the filename. * @param {Object} filename - The filename to remove the filter from * @returns {string} The filename without the filter part */ function stripFilter (filename) { return filename.substring(0, filename.length - filterOn.length - 1) } /** * Get the relative path to the file by removing the starting directory (buildDestPath) from the file path. * @param {string} filePath - Fully qualified path of the file to get the relative path for * @param {string} buildDistPath - Fully qualified path to the start directory, which is subtracted from the filePath * to get the relative path * @returns {string} relative file path to the module */ function stripBuildDest (filePath, buildDestPath) { return filePath.substring(buildDestPath.length) } /** * Remove the file extension from the file path. * @param {string} filePath - Fully qualified path of the file to remove the file extension from * @returns {string} Fully qualified path of the file without the file extension */ function stripExt (filePath) { const ext = path.extname(filePath) return filePath.substring(0, filePath.length - ext.length) } /** * @typedef {Object} ModuleParts * @property {string} moduleName - The module name * @property {string} modulePath - The relative path starting from the buildDistPath */ /** * Creates a module parts object that contains the name and relative path to the module based on the file path from * which the base path (buildDestPath) is extracted. It also converts kebab case to capitalized words without spaces, * i.e. hello-world to HelloWorld. * @param {string} filePath - Fully qualified name of the file to create the module parts for * @param {string} buildDistPath - Fully qualified path to the start directory, which is subtracted from the filePath * to get the relative path * @returns {ModuleParts} an object with the module parts */ function getModuleParts (filePath, buildDistPath) { filePath = correctPathSeparator(filePath) // Convert kebab case to capitalized words without spaces, i.e. hello-world to HelloWorld const moduleName = upperCamelCase(stripFilter(path.basename(filePath))) const modulePath = stripExt(stripBuildDest(filePath, buildDistPath)) return { moduleName, modulePath } } /** * Creates a named export statement. * @param {Object} moduleParts - An object with the module parts that are extracted from the filename * @returns {string} a named export statement */ function createNamedExport (moduleParts) { return 'import ' + moduleParts.moduleName + ' from \'.' + moduleParts.modulePath + '\'' } /** * Creates a default export statement. * @param {Object} moduleParts - An object with the module parts that are extracted from the filename * @returns {string} a default export statement */ function createDefaultExport (moduleParts) { return 'export default ' + moduleParts.moduleName } /** * Create named exports in the index.js file places in the start directory. * @param {Array<String>} files - An array with fully qualified paths to the files to process * @param {string} exportsFilePath - Fully qualified path to the index.js file in the start directory * @param {string} buildDestPath - A fully qualified path to the directory to start processing from * @returns {Promise<void>} a promise */ async function processFiles (files, exportsFilePath, buildDestPath) { // Make sure we remove the old exports file deleteFile(exportsFilePath) if (files.length === 0) { !quiet && console.log('No components to process') } else { let contents = [] if (files.length === 1) { // One file found, add named and default exports const moduleParts = getModuleParts(files[0], buildDestPath) contents.push(createNamedExport(moduleParts)) contents.push(createDefaultExport(moduleParts)) !quiet && console.log('One component found, set named and default export') } else { // Multiple files found, only add named exports files.forEach(file => { const moduleParts = getModuleParts(file, buildDestPath) contents.push(createNamedExport(moduleParts)) }) !quiet && console.log(files.length + ' components found, set named exports only') } const fs = require('fs') fs.writeFileSync(exportsFilePath, contents.join('\n')) } } /** * Retrieve files (buildDestPath) that meet a specific filename filter. It recursively search from this start directory * for any files that match the file filter. * @param {string} buildDestPath - A fully qualified path to the directory to start processing from * @returns {Array} with files to process */ function getFiles (buildDestPath) { const files = FileHound.create() .paths(buildDestPath) .addFilter(customFilter) .findSync() return files } /** * Main entry point to module creates the index.js file with named exports (multiple components) or default and * named (single component). * * Takes the following option object: * { * buildDestPath: the start directory to start searching for any files that match the file filter (*.common.js) to * add eslint disable to (multi file mode) and create export entries for in index.js that is placed * in the start directory. * if not specified it uses a sane default: dist * verbose: output debugging information, default false * quiet: report errors only, default false * } * * @param {Object} options - See description above */ function createExports (options) { debug = options && options.debug ? options.debug : false verbose = options && options.verbose ? options.verbose : false quiet = options && options.quiet ? options.quiet : false debug && console.log('create-exports', JSON.stringify(options, null, '\t')) // Use sane default (dist) if not specified options.buildDestPath = options.buildDestPath || defaultDestPath if (!directoryExists(options.buildDestPath)) { throw Error('Build directory does not exist: ' + options.buildDestPath) } const exportsFilePath = path.join(options.buildDestPath, 'index.js') debug && console.log('Exports file: ' + exportsFilePath) const files = getFiles(options.buildDestPath) processFiles(files, exportsFilePath, options.buildDestPath) .then(() => { if (verbose && files.length > 0) console.log('Export file created') else console.log('No export file created') }) } module.exports = createExports