With the continuous expansion and maturation of Vue3 ecology, Vue3 has stepped into the production project from the initial stage. Along with the development scaffolding update, the new Vite scaffolding, esbuild based use of go language performance advantages, compared to Webpack has not an order of magnitude of performance advantages, packaging based on Rollup expansion, inherit the advantages of lightweight and bright plug-in Api.
What, you don’t know? You should hold on tight.
Vue3 official Chinese document
Vite official Chinese document
Blah, blah, blah, blah, blah, blah, blah, blah.
Create a project
This article focuses on generating type declaration files, so the project creation section is just a brief description.
Build a simple project quickly using official templates:
yarn create @vitejs/app my-vue-app --template vue-ts
Copy the code
Then rename SRC /main.ts to SRC /index.ts and modify its contents:
export { default as App } from './App.vue'
Copy the code
Never mind the name App, let’s just assume we wrote a component and exported it as a plug-in.
Then adjust the vite.config.ts configuration to library mode packaging:
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'Plugin'.formats: ['es'].fileName: 'index'}},plugins: [vue()]
})
Copy the code
At this point, a simple plug-in project is complete.
Generate a type declaration file
Rollup-plugin-typescript2 is used to generate.d.ts declaration files from source code.
Vue files can’t be parsed. vue files can’t be parsed. vue files can’t be parsed. vue files can’t be parsed. Vite + Vue3 doesn’t support typescript.
Of course, some people in the issue want Vite to support the export of declaration files when the library mode is packaged, but the Vite official said that they do not want to increase the maintenance burden and structural complexity.
So in Vite development, we had to come up with other ways to generate declaration files.
The generation method described in this article relies on some existing libraries, and then some programming scripts to achieve the purpose, after all, there is not enough space to start with packaging principles.
Install the library used to build the declaration file:
yarn add ts-morph -D
Copy the code
The core of the.vue file’s intention to generate a type declaration file is to extract the contents of the
Start writing our script after creating new scripts/build-types.js.
const path = require('path')
const fs = require('fs')
const glob = require('fast-glob')
const { Project } = require('ts-morph')
const { parse, compileScript } = require('@vue/compiler-sfc')
let index = 1
main()
async function main() {
// Please refer to the ts-MORph documentation for details about this section
// This is used to process the ts file and generate the type declaration file
const project = new Project({
compilerOptions: {
declaration: true.emitDeclarationOnly: true.noEmitOnError: true.allowJs: true.// If you want to be compatible with JS syntax, you need to add it
outDir: 'dist' // You can set custom packing folders such as 'types'
},
tsConfigFilePath: path.resolve(__dirname, '.. /tsconfig.json'),
skipAddingFilesFromTsConfig: true
})
// Get.vue and.ts files under SRC
const files = await glob(['src/**/*.ts'.'src/**/*.vue'])
const sourceFiles = []
await Promise.all(
files.map(async file => {
if (/\.vue$/.test(file)) {
// For vue files, parse with @vue/ compiler-SFC
const sfc = parse(await fs.promises.readFile(file, 'utf-8'))
// Extract the contents of script
const { script, scriptSetup } = sfc.descriptor
if (script || scriptSetup) {
let content = ' '
let isTs = false
if (script && script.content) {
content += script.content
if (script.lang === 'ts') isTs = true
}
if (scriptSetup) {
const compiled = compileScript(sfc.descriptor, {
id: `${index++}`
})
content += compiled.content
if (scriptSetup.lang === 'ts') isTs = true
}
sourceFiles.push(
// Create a ts/js mapping file with the same path
project.createSourceFile(file + (isTs ? '.ts' : '.js'), content)
)
}
} else {
// If it is a ts file, add it directly
sourceFiles.push(project.addSourceFileAtPath(file))
}
})
)
const diagnostics = project.getPreEmitDiagnostics()
// Output error information during parsing
console.log(project.formatDiagnosticsWithColorAndContext(diagnostics))
project.emitToMemory()
// Then write the parsed file to the package path
for (const sourceFile of sourceFiles) {
const emitOutput = sourceFile.getEmitOutput()
for (const outputFile of emitOutput.getOutputFiles()) {
const filePath = outputFile.getFilePath()
await fs.promises.mkdir(path.dirname(filePath), { recursive: true })
await fs.promises.writeFile(filePath, outputFile.getText(), 'utf8')}}}Copy the code
Add a command to package type files in package.json:
{
"scripts": {
"build:types": "node scripts/build-types.js"}}Copy the code
In the project root directory, run the following command:
yarn run build:types
Copy the code
You can see that the dist directory now has index.d.ts, app.vue.d. ts and other type declaration files.
Vite plug-in
In Vite packaging, the @vitejs/plugin-vue plugin compiles and splits the.vue file into three parts, including templates, scripts and styles. We just need to take the content of the compiled part of the script, and through the above method, we can easily generate the type declaration file without even compiling the file ourselves.
Create plugins/dts.ts and start with the following code:
import { resolve, dirname } from 'path'
import fs from 'fs/promises'
import { createFilter } from '@rollup/pluginutils'
import { normalizePath } from 'vite'
import { Project } from 'ts-morph'
import type { Plugin } from 'vite'
import type { SourceFile } from 'ts-morph'
export default() :Plugin= > {
const filter = createFilter(['**/*.vue'.'**/*.ts'].'node_modules/**')
const sourceFiles: SourceFile[] = []
const project = new Project({
compilerOptions: {
declaration: true.emitDeclarationOnly: true.noEmitOnError: true.allowJs: true.// If you want to be compatible with JS syntax, you need to add it
outDir: 'dist' // You can set custom packing folders such as 'types'
},
tsConfigFilePath: resolve(__dirname, '.. /tsconfig.json'),
skipAddingFilesFromTsConfig: true
})
let root: string
return {
name: 'gen-dts'.apply: 'build'.enforce: 'pre'.// You need to be in pre to get the ts script properly
configResolved(config) {
root = config.root
},
transform(code, id) {
if(! code || ! filter(id))return null
// The split file ID has some characteristics that can be captured in a regular manner
if (/\.vue(\? .*type=script.*)$/.test(id)) {
const filePath = resolve(root, normalizePath(id.split('? ') [0]))
sourceFiles.push(
project.createSourceFile(filePath + (/lang.ts/.test(id) ? '.ts' : '.js'), code)
)
} else if (/\.ts$/.test(id)) {
const filePath = resolve(root, normalizePath(id))
sourceFiles.push(project.addSourceFileAtPath(filePath))
}
},
async generateBundle() {
const diagnostics = project.getPreEmitDiagnostics()
// Output error information during parsing
console.log(project.formatDiagnosticsWithColorAndContext(diagnostics))
project.emitToMemory()
// Then write the parsed file to the package path
for (const sourceFile of sourceFiles) {
const emitOutput = sourceFile.getEmitOutput()
for (const outputFile of emitOutput.getOutputFiles()) {
const filePath = outputFile.getFilePath()
await fs.mkdir(dirname(filePath), { recursive: true })
await fs.writeFile(filePath, outputFile.getText(), 'utf8')}}}}}Copy the code
So easy, a simple DTS plug-in is done.
We just need to reference the plugin in viet.config.ts:
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import dts from './plugins/dts'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'Plugin'.formats: ['es'].fileName: 'index'}},plugins: [vue(), dts()]
})
Copy the code
Then execute the original command and you can see the packaging and generation of the type declaration file in one go:
yarn run build
Copy the code
Write in the last
Of course, the above plug-in only contains the most basic functions, the author wrote a plug-in that covers more extensive functions, the source code has been put on Github, and NPM has also been released.
yarn add vite-plugin-dts -D
Copy the code
Welcome to use and feedback, if you think this is helpful, please also like, favorites, and a reward ⭐.
Plugin address: github.com/qmhc/vite-p…
Finally, I secretly amway my Vue3 component library, which is mainly used for the company’s project: VEXIP-UI
In this paper, starting from segmentfault.com/a/119000004…