Skip to content
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

feat: support sourcemap generation #70

Merged
merged 1 commit into from Nov 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/vite-plugin-vue-i18n/examples/legacy/main.ts
@@ -1,12 +1,16 @@
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'
import messages from '@intlify/vite-plugin-vue-i18n/messages'
import en from './locales/en.yaml'
import ja from './locales/ja.json'

const i18n = createI18n({
legacy: true,
locale: 'ja',
messages
messages: {
en,
ja
}
})

const app = createApp(App)
Expand Down
1 change: 1 addition & 0 deletions packages/vite-plugin-vue-i18n/package.json
Expand Up @@ -27,6 +27,7 @@
"@intlify/shared": "beta",
"@rollup/pluginutils": "^4.1.0",
"debug": "^4.3.1",
"source-map": "0.6.1",
"fast-glob": "^3.2.5"
},
"devDependencies": {},
Expand Down
63 changes: 44 additions & 19 deletions packages/vite-plugin-vue-i18n/src/index.ts
Expand Up @@ -10,6 +10,7 @@ import {
import fg from 'fast-glob'
import createDebug from 'debug'
import { normalizePath } from 'vite'
import { RawSourceMap } from 'source-map'
import { parseVueRequest } from './query'

import type { Plugin, ResolvedConfig, UserConfig } from 'vite'
Expand Down Expand Up @@ -70,7 +71,9 @@ function pluginI18n(
? 'vue-i18n'
: `${installedPkg}`
const forceStringify = !!options.forceStringify

let isProduction = false
let sourceMap = false

return {
name: 'vite-plugin-vue-i18n',
Expand Down Expand Up @@ -129,6 +132,7 @@ function pluginI18n(

configResolved(config: ResolvedConfig) {
isProduction = config.isProduction
sourceMap = config.command === 'build' ? !!config.build.sourcemap : false

// json transform handling
const jsonPlugin = config.plugins.find(p => p.name === 'vite:json')
Expand Down Expand Up @@ -167,13 +171,15 @@ function pluginI18n(
for (const inc of includePaths) {
resourcePaths = [...(await fg(inc))]
}
// TODO: source-map
const code = await generateBundleResources(
resourcePaths,
isProduction,
forceStringify
)
return Promise.resolve(code)
return Promise.resolve({
code,
map: { mappings: '' }
})
}
},

Expand All @@ -194,17 +200,12 @@ function pluginI18n(
debug('transform', id, JSON.stringify(query))

let langInfo = 'json'
let inSourceMap: RawSourceMap | undefined

if (!query.vue) {
if (/\.(json5?|ya?ml)$/.test(id) && filter(id)) {
langInfo = path.parse(filename).ext

// NOTE:
// `.json` is handled default in vite, and it's transformed to JS object.
let _source = code
if (langInfo === '.json') {
_source = await getRaw(id)
}

const generate = /\.?json5?/.test(langInfo)
? generateJSON
: generateYAML
Expand All @@ -213,17 +214,26 @@ function pluginI18n(
filename,
isProduction,
query as Record<string, unknown>,
sourceMap,
inSourceMap,
globalSFCScope,
forceStringify
) as CodeGenOptions
debug('parseOptions', parseOptions)

const { code: generatedCode } = generate(_source, parseOptions)
debug('generated code', generatedCode)
// TODO: error handling & sourcempa
return Promise.resolve(generatedCode)
const { code: generatedCode, map } = generate(code, parseOptions)
debug('generated code', generatedCode, id)
debug('sourcemap', map, id)

return Promise.resolve({
code: generatedCode,
map: (sourceMap ? map : { mappings: '' }) as any // eslint-disable-line @typescript-eslint/no-explicit-any
})
} else {
return Promise.resolve(code)
return Promise.resolve({
code,
map: sourceMap ? this.getCombinedSourcemap() : { mappings: '' }
})
}
} else {
// for Vue SFC
Expand All @@ -246,17 +256,26 @@ function pluginI18n(
filename,
isProduction,
query as Record<string, unknown>,
sourceMap,
inSourceMap,
globalSFCScope,
forceStringify
) as CodeGenOptions
debug('parseOptions', parseOptions)

const { code: generatedCode } = generate(code, parseOptions)
debug('generated code', generatedCode)
// TODO: error handling & sourcempa
return Promise.resolve(generatedCode)
const { code: generatedCode, map } = generate(code, parseOptions)
debug('generated code', generatedCode, id)
debug('sourcemap', map, id)

return Promise.resolve({
code: generatedCode,
map: (sourceMap ? map : { mappings: '' }) as any // eslint-disable-line @typescript-eslint/no-explicit-any
})
} else {
return Promise.resolve(code)
return Promise.resolve({
code,
map: sourceMap ? this.getCombinedSourcemap() : { mappings: '' }
})
}
}
}
Expand Down Expand Up @@ -295,13 +314,17 @@ function getOptions(
filename: string,
isProduction: boolean,
query: Record<string, unknown>,
sourceMap: boolean,
inSourceMap: RawSourceMap | undefined,
isGlobal = false,
forceStringify = false
): Record<string, unknown> {
const mode: DevEnv = isProduction ? 'production' : 'development'

const baseOptions = {
filename,
sourceMap,
inSourceMap,
forceStringify,
env: mode,
onWarn: (msg: string): void => {
Expand Down Expand Up @@ -344,6 +367,8 @@ async function generateBundleResources(
res,
isProduction,
{},
false,
undefined,
isGlobal,
forceStringify
) as CodeGenOptions
Expand Down
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`custom blocks json 1`] = `";;;;;;;;;;;;;;;;;;;;;;AAIE;SACO;;;"`;

exports[`custom blocks json5 1`] = `";;;;;;;;;;;;;;;;;;;;;;AAIE;SACO;;;"`;

exports[`custom blocks yaml 1`] = `";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIE;SACO;;;"`;

exports[`custom blocks yml 1`] = `";;;;;;;;;;;;;;;;;;;;AAIE;SACO;;;"`;

exports[`resource files json 1`] = `";;;2EACYA,gDAAAC;;;;;wBAEAC;;;;;;;;;;;;;;;;;;;;;;ACCV;SACO;;;"`;

exports[`resource files json5 1`] = `";;;;;;;;;;;AAIE;SACO;;;"`;

exports[`resource files yaml 1`] = `";;;;;;;;;;;AAIE;SACO;;;"`;
3 changes: 3 additions & 0 deletions packages/vite-plugin-vue-i18n/test/fixtures/yml.vue
@@ -0,0 +1,3 @@
<i18n lang="yml">
message: "@.caml:{'no apples'} | {0} apple | {n} apples"
</i18n>
47 changes: 47 additions & 0 deletions packages/vite-plugin-vue-i18n/test/sourcemap.test.ts
@@ -0,0 +1,47 @@
import path from 'path'
import { bundleAndRun } from './utils'

describe('resource files', () => {
const options = {
sourcemap: true,
target: './fixtures/locales/',
include: [path.resolve(__dirname, './fixtures/locales/**')]
}

test('json', async () => {
const { map } = await bundleAndRun('ja.json', options)
expect(map.mappings).toMatchSnapshot()
})

test('json5', async () => {
const { map } = await bundleAndRun('en.json5', options)
expect(map.mappings).toMatchSnapshot()
})

test('yaml', async () => {
const { map } = await bundleAndRun('ko.yaml', options)
expect(map.mappings).toMatchSnapshot()
})
})

describe('custom blocks', () => {
test('json', async () => {
const { map } = await bundleAndRun('basic.vue', { sourcemap: true })
expect(map.mappings).toMatchSnapshot()
})

test('yaml', async () => {
const { map } = await bundleAndRun('yaml.vue', { sourcemap: true })
expect(map.mappings).toMatchSnapshot()
})

test('yml', async () => {
const { map } = await bundleAndRun('yml.vue', { sourcemap: true })
expect(map.mappings).toMatchSnapshot()
})

test('json5', async () => {
const { map } = await bundleAndRun('json5.vue', { sourcemap: true })
expect(map.mappings).toMatchSnapshot()
})
})
14 changes: 11 additions & 3 deletions packages/vite-plugin-vue-i18n/test/utils.ts
Expand Up @@ -13,6 +13,7 @@ async function bundle(fixture: string, options: Record<string, unknown> = {}) {
const include = (options.include as string[]) || [
path.resolve(__dirname, './fixtures/**')
]
const sourcemap = (options.sourcemap as boolean) || false
const silent = isBoolean(options.silent)
? options.silent === false
? 'info'
Expand Down Expand Up @@ -46,22 +47,27 @@ async function bundle(fixture: string, options: Record<string, unknown> = {}) {
},
plugins,
build: {
sourcemap,
write: false,
minify: false,
rollupOptions: {
input: path.resolve(__dirname, input)
}
}
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return { code: (result as any).output[0].code }
return {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
code: (result as any).output[0].code,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
map: (result as any).output[0].map
}
}

export async function bundleAndRun(
fixture: string,
options: Record<string, unknown> = {}
) {
const { code } = await bundle(fixture, options)
const { code, map } = await bundle(fixture, options)

let dom: JSDOM | null = null
let jsdomError
Expand All @@ -87,6 +93,8 @@ export async function bundleAndRun(
window,
module,
exports,
code,
map,
jsdomError
})
}