Skip to content

feat: Support vue.config.ts #6820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// Todo: reduce test time. (e.g. esbuild-jest, swc-jest)
module.exports = {
'testEnvironment': 'node',
'setupFiles': [
'<rootDir>/scripts/testSetup.js'
],
'testMatch': [
'**/__tests__/**/*.spec.js'
]
testEnvironment: 'node',
setupFiles: ['<rootDir>/scripts/testSetup.js'],
testMatch: ['**/__tests__/**/*.spec.js']
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ test('should inject polyfills / helpers using "import" statements for an es modu
new Promise()
`.trim(), {
babelrc: false,
configFile: false,
presets: [[preset, {
targets: { ie: 9 },
absoluteRuntime: false
Expand Down
8 changes: 5 additions & 3 deletions packages/@vue/cli-service/__tests__/Service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ beforeEach(() => {
delete process.env.BAZ
})

const removeFile = p => {
if (fs.existsSync(p)) fs.unlinkSync(p)
}

afterEach(() => {
if (fs.existsSync('/vue.config.js')) {
fs.unlinkSync('/vue.config.js')
}
removeFile('/vue.config.js')
})

test('env loading', async () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/@vue/cli-service/__tests__/ServiceESM.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@ test('load project options from vue.config.mjs', async () => {
expect(service.projectOptions.lintOnSave).toBe(true)
await fs.unlinkSync(configPath)
})

test('load project options from vue.config.ts', async () => {
const configPath = path.resolve(project.dir, './vue.config.ts')
fs.writeFileSync(configPath, `
const lintOnSave:boolean = true
export default { lintOnSave }
`)
const service = await createService()
expect(service.projectOptions.lintOnSave).toBe(true)
await fs.unlinkSync(configPath)
})
120 changes: 92 additions & 28 deletions packages/@vue/cli-service/lib/util/loadFileConfig.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,102 @@
const fs = require('fs')
const path = require('path')

const isFileEsm = require('is-file-esm')
// @ts-check
const { existsSync, unlinkSync, promises } = require('fs')
const { join, extname, isAbsolute, dirname } = require('path')
const { build } = require('esbuild')
// @ts-ignore
const { loadModule } = require('@vue/cli-shared-utils')

module.exports = function loadFileConfig (context) {
let fileConfig, fileConfigPath

const possibleConfigPaths = [
process.env.VUE_CLI_SERVICE_CONFIG_PATH,
'./vue.config.js',
'./vue.config.cjs',
'./vue.config.mjs'
]
for (const p of possibleConfigPaths) {
const resolvedPath = p && path.resolve(context, p)
if (resolvedPath && fs.existsSync(resolvedPath)) {
fileConfigPath = resolvedPath
break
}
const POSSIBLE_CONFIG_PATHS = [
process.env.VUE_CLI_SERVICE_CONFIG_PATH,
'vue.config.js',
'vue.config.cjs',
'vue.config.mjs',
'vue.config.ts'
].filter((i) => !!i)

const removeFile = (p) => {
if (existsSync(p)) unlinkSync(p)
}

const bundleConfig = async (p, ctx, mjs = false) => {
const outFile = p.replace(/\.[a-z]+$/, '.bundled.js')
const readConfig = () => {
// eslint-disable-next-line
delete eval(`require.cache`)[outFile]
const result = mjs ? import(outFile) : require(outFile)
removeFile(outFile)
return result.default || result
}

if (fileConfigPath) {
const { esm } = isFileEsm.sync(fileConfigPath)
try {
await build({
absWorkingDir: ctx,
entryPoints: [p],
outfile: outFile,
platform: 'node',
bundle: true,
target: 'es2017',
format: mjs ? 'esm' : 'cjs',
plugins: [
{
name: 'ignore',
setup (bld) {
bld.onResolve({ filter: /.*/ }, (args) => {
// eslint-disable-next-line
if (!isAbsolute(args.path) && !/^[\.\/]/.test(args.path)) {
return { external: true }
}
})
bld.onLoad(
{ filter: /\.(js|ts|mjs|cjs)$/ },
// @ts-ignore
async (args) => {
const contents = await promises.readFile(args.path, 'utf8')
return {
contents: contents
.replace(/\b__dirname\b/g, JSON.stringify(dirname(args.path)))
.replace(/\b__filename\b/g, JSON.stringify(args.path))
.replace(/\bimport\.meta\.url\b/g, JSON.stringify(`file://${args.path}`)),
loader: args.path.endsWith('.ts') ? 'ts' : 'js'
}
}
)
}
}
]
})
return readConfig()
} catch (e) {
removeFile(outFile)
throw e
}
}

function loadFileConfig (context) {
let fileConfig

if (esm) {
fileConfig = import(fileConfigPath)
} else {
fileConfig = loadModule(fileConfigPath, context)
const formatPath = (p) => join(context, p)
const getPkg = () => {
try {
return require(formatPath('package.json'))
} catch (e) {
return {}
}
}

return {
fileConfig,
fileConfigPath
const fileConfigPath = POSSIBLE_CONFIG_PATHS.map(formatPath).find((p) => existsSync(p))
const ext = extname(fileConfigPath || '')
const isMjs = (ext === '.js' && getPkg().type === 'module') || ext === '.mjs'

if (isMjs) {
fileConfig = import(fileConfigPath)
} else if (ext === '.ts') {
// use esbuild to compile .ts config
fileConfig = bundleConfig(fileConfigPath, context, true)
} else if (ext) {
fileConfig = loadModule(fileConfigPath, context)
}

return { fileConfig, fileConfigPath }
}

module.exports = loadFileConfig
2 changes: 1 addition & 1 deletion packages/@vue/cli-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@
"default-gateway": "^6.0.3",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"esbuild": "0.13.12",
"fs-extra": "^9.1.0",
"globby": "^11.0.2",
"hash-sum": "^2.0.0",
"html-webpack-plugin": "^5.1.0",
"is-file-esm": "^1.0.0",
"launch-editor-middleware": "^2.2.1",
"lodash.defaultsdeep": "^4.6.1",
"lodash.mapvalues": "^4.6.0",
Expand Down
Loading