123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- const path = require('path')
- const hash = require('hash-sum')
- const { semver, matchesPluginId } = require('@vue/cli-shared-utils')
- // Note: if a plugin-registered command needs to run in a specific default mode,
- // the plugin needs to expose it via `module.exports.defaultModes` in the form
- // of { [commandName]: mode }. This is because the command mode needs to be
- // known and applied before loading user options / applying plugins.
- class PluginAPI {
- /**
- * @param {string} id - Id of the plugin.
- * @param {Service} service - A vue-cli-service instance.
- */
- constructor (id, service) {
- this.id = id
- this.service = service
- }
- get version () {
- return require('../package.json').version
- }
- assertVersion (range) {
- if (typeof range === 'number') {
- if (!Number.isInteger(range)) {
- throw new Error('Expected string or integer value.')
- }
- range = `^${range}.0.0-0`
- }
- if (typeof range !== 'string') {
- throw new Error('Expected string or integer value.')
- }
- if (semver.satisfies(this.version, range, { includePrerelease: true })) return
- throw new Error(
- `Require @vue/cli-service "${range}", but was loaded with "${this.version}".`
- )
- }
- /**
- * Current working directory.
- */
- getCwd () {
- return this.service.context
- }
- /**
- * Resolve path for a project.
- *
- * @param {string} _path - Relative path from project root
- * @return {string} The resolved absolute path.
- */
- resolve (_path) {
- return path.resolve(this.service.context, _path)
- }
- /**
- * Check if the project has a given plugin.
- *
- * @param {string} id - Plugin id, can omit the (@vue/|vue-|@scope/vue)-cli-plugin- prefix
- * @return {boolean}
- */
- hasPlugin (id) {
- return this.service.plugins.some(p => matchesPluginId(id, p.id))
- }
- /**
- * Register a command that will become available as `vue-cli-service [name]`.
- *
- * @param {string} name
- * @param {object} [opts]
- * {
- * description: string,
- * usage: string,
- * options: { [string]: string }
- * }
- * @param {function} fn
- * (args: { [string]: string }, rawArgs: string[]) => ?Promise
- */
- registerCommand (name, opts, fn) {
- if (typeof opts === 'function') {
- fn = opts
- opts = null
- }
- this.service.commands[name] = { fn, opts: opts || {}}
- }
- /**
- * Register a function that will receive a chainable webpack config
- * the function is lazy and won't be called until `resolveWebpackConfig` is
- * called
- *
- * @param {function} fn
- */
- chainWebpack (fn) {
- this.service.webpackChainFns.push(fn)
- }
- /**
- * Register
- * - a webpack configuration object that will be merged into the config
- * OR
- * - a function that will receive the raw webpack config.
- * the function can either mutate the config directly or return an object
- * that will be merged into the config.
- *
- * @param {object | function} fn
- */
- configureWebpack (fn) {
- this.service.webpackRawConfigFns.push(fn)
- }
- /**
- * Register a dev serve config function. It will receive the express `app`
- * instance of the dev server.
- *
- * @param {function} fn
- */
- configureDevServer (fn) {
- this.service.devServerConfigFns.push(fn)
- }
- /**
- * Resolve the final raw webpack config, that will be passed to webpack.
- *
- * @param {ChainableWebpackConfig} [chainableConfig]
- * @return {object} Raw webpack config.
- */
- resolveWebpackConfig (chainableConfig) {
- return this.service.resolveWebpackConfig(chainableConfig)
- }
- /**
- * Resolve an intermediate chainable webpack config instance, which can be
- * further tweaked before generating the final raw webpack config.
- * You can call this multiple times to generate different branches of the
- * base webpack config.
- * See https://github.com/mozilla-neutrino/webpack-chain
- *
- * @return {ChainableWebpackConfig}
- */
- resolveChainableWebpackConfig () {
- return this.service.resolveChainableWebpackConfig()
- }
- /**
- * Generate a cache identifier from a number of variables
- */
- genCacheConfig (id, partialIdentifier, configFiles = []) {
- const fs = require('fs')
- const cacheDirectory = this.resolve(`node_modules/.cache/${id}`)
- // replace \r\n to \n generate consistent hash
- const fmtFunc = conf => {
- if (typeof conf === 'function') {
- return conf.toString().replace(/\r\n?/g, '\n')
- }
- return conf
- }
- const variables = {
- partialIdentifier,
- 'cli-service': require('../package.json').version,
- 'cache-loader': require('cache-loader/package.json').version,
- env: process.env.NODE_ENV,
- test: !!process.env.VUE_CLI_TEST,
- config: [
- fmtFunc(this.service.projectOptions.chainWebpack),
- fmtFunc(this.service.projectOptions.configureWebpack)
- ]
- }
- if (!Array.isArray(configFiles)) {
- configFiles = [configFiles]
- }
- configFiles = configFiles.concat([
- 'package-lock.json',
- 'yarn.lock',
- 'pnpm-lock.yaml'
- ])
- const readConfig = file => {
- const absolutePath = this.resolve(file)
- if (!fs.existsSync(absolutePath)) {
- return
- }
- if (absolutePath.endsWith('.js')) {
- // should evaluate config scripts to reflect environment variable changes
- try {
- return JSON.stringify(require(absolutePath))
- } catch (e) {
- return fs.readFileSync(absolutePath, 'utf-8')
- }
- } else {
- return fs.readFileSync(absolutePath, 'utf-8')
- }
- }
- variables.configFiles = configFiles.map(file => {
- const content = readConfig(file)
- return content && content.replace(/\r\n?/g, '\n')
- })
- const cacheIdentifier = hash(variables)
- return { cacheDirectory, cacheIdentifier }
- }
- }
- module.exports = PluginAPI
|