如何让 ts-transformer-keys 与 Vue 一起工作
How to get ts-transformer-keys working with Vue
编辑:
现在我觉得自己像个白痴...从昨天晚上开始我就一直在做这件事。今天我意识到我可以测试将 transpileOnly 解析为 false:
chainWebpack: config => {
const getCustomTransformers = program => ({
before: [keysTransformer(program)]
});
const transpileOnly = false;
["ts", "tsx"].forEach(rule => {
config.module
.rule(rule)
.use("ts-loader")
.loader("ts-loader")
.tap(options => Object.assign(options, { getCustomTransformers, transpileOnly }));
});
},
而且..这确实有效。我在控制台中看到了我的界面键。我现在唯一的问题是——这样做会破坏什么?如果我这样做不安全,还有其他更好的方法吗?
来源:
此刻,我的怀疑(从最后一段)是 ts-loader 的 transpileOnly: true,
选项与 transformers 不兼容...如果是这样,有什么办法吗?只是对我的想法的确认或否定就会非常棒。有问题的变压器是 Kenji Imamula 的 ts-transformer-keys
我认为你需要熟悉 webpack 和 typescript,才能让它工作。如果你像我一样,专业地使用它但不涉及核心功能,你可能会喜欢这个变形金刚入门:how to write a TypeScript transform plugin
我在 wepack 方面非常有能力,所以我希望它能正常工作。但是,我是第一次使用 vue 3,webpack 是..不同的。你使用 vue.config.js 来设置一个块来使用 webpack-merge 或 webpack-chain 修改 webpack 配置。因为我想改变 ts 加载器(我假设),我使用了 chain.. 我还做了一些其他配置更改,所以我的 vue.config.ts 看起来像这样:
const PackageVars = require('./package-vars.webpack-plugin.js')
const keysTransformer = require('ts-transformer-keys/transformer').default
module.exports = {
configureWebpack: {
plugins: [PackageVars]
},
chainWebpack: config => {
const getCustomTransformers = program => ({
before: [keysTransformer(program)]
})
;['ts', 'tsx'].forEach(rule => {
config.module
.rule(rule)
.use('ts-loader')
.loader('ts-loader')
.tap(options => Object.assign(options, { getCustomTransformers }))
})
},
pluginOptions: {
i18n: {
locale: 'en',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: true
}
},
css: {
loaderOptions: {
sass: {
prependData: `@import "@/styles/global.scss";`
}
}
}
}
并生成一个 webpack.config.js(据 vue inspect 报告,这是缩写,主要是删除 css 相关的编译,因为 Whosebug 中的字符限制):
{
mode: 'development',
context: '/Users/me/Public/project',
node: {
setImmediate: false,
process: 'mock',
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
//...
resolveLoader: {
modules: [
'/Users/me/Public/project/node_modules/@vue/cli-plugin-typescript/node_modules',
'/Users/me/Public/project/node_modules/@vue/cli-plugin-babel/node_modules',
'node_modules',
'/Users/me/Public/project/node_modules',
'/Users/me/Public/project/node_modules/@vue/cli-service/node_modules'
]
},
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
rules: [
/* config.module.rule('vue') */
{
test: /\.vue$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/vue-loader',
cacheIdentifier: '1fc0539f'
}
},
{
loader: '/Users/me/Public/project/node_modules/vue-loader/lib/index.js',
options: {
compilerOptions: {
whitespace: 'condense'
},
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/vue-loader',
cacheIdentifier: '1fc0539f'
}
}
]
},
//...
/* config.module.rule('js') */
{
test: /\.m?jsx?$/,
exclude: [
function () { /* omitted long function */ }
],
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/babel-loader',
cacheIdentifier: '0fff5c38'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
}
]
},
/* config.module.rule('eslint') */
{
enforce: 'pre',
test: /\.(vue|(j|t)sx?)$/,
exclude: [
/node_modules/,
'/Users/me/Public/project/node_modules/@vue/cli-service/lib'
],
use: [
{
loader: '/Users/me/Public/project/node_modules/eslint-loader/index.js',
options: {
extensions: [
'.js',
'.jsx',
'.vue',
'.ts',
'.tsx'
],
cache: true,
cacheIdentifier: '5749dfb1',
emitWarning: false,
emitError: false,
eslintPath: '/Users/me/Public/project/node_modules/eslint',
formatter: function () { /* omitted long function */ }
}
}
]
},
/* config.module.rule('ts') */
{
test: /\.ts$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/ts-loader',
cacheIdentifier: 'b1785fd2'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: [
'\.vue$'
],
happyPackMode: false,
getCustomTransformers: program => ({
before: [keysTransformer(program)]
})
}
}
]
},
/* config.module.rule('tsx') */
{
test: /\.tsx$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/ts-loader',
cacheIdentifier: 'b1785fd2'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
happyPackMode: false,
appendTsxSuffixTo: [
'\.vue$'
],
getCustomTransformers: program => ({
before: [keysTransformer(program)]
})
}
}
]
},
/* config.module.rule('i18n') */
{
resourceQuery: /blockType=i18n/,
type: 'javascript/auto',
use: [
{
loader: '@kazupon/vue-i18n-loader'
}
]
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\/]node_modules[\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
},
minimizer: [
{
options: {
test: /\.m?js(\?.*)?$/i,
chunkFilter: () => true,
warningsFilter: () => true,
extractComments: false,
sourceMap: true,
cache: true,
cacheKeys: defaultCacheKeys => defaultCacheKeys,
parallel: true,
include: undefined,
exclude: undefined,
minify: undefined,
terserOptions: {
compress: {
arrows: false,
collapse_vars: false,
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
booleans: true,
if_return: true,
sequences: true,
unused: true,
conditionals: true,
dead_code: true,
evaluate: true
},
mangle: {
safari10: true
}
}
}
}
]
},
plugins: [
/* config.plugin('vue-loader') */
new VueLoaderPlugin(),
/* config.plugin('define') */
new DefinePlugin(
{
'process.env': {
NODE_ENV: '"development"',
VUE_APP_I18N_LOCALE: '"en"',
VUE_APP_I18N_FALLBACK_LOCALE: '"en"',
BASE_URL: '"/"'
}
}
),
/* config.plugin('case-sensitive-paths') */
new CaseSensitivePathsPlugin(),
/* config.plugin('friendly-errors') */
new FriendlyErrorsWebpackPlugin(
{
additionalTransformers: [
function () { /* omitted long function */ }
],
additionalFormatters: [
function () { /* omitted long function */ }
]
}
),
/* config.plugin('html') */
new HtmlWebpackPlugin(
{
templateParameters: function () { /* omitted long function */ },
template: '/Users/me/Public/project/public/index.html'
}
),
/* config.plugin('pwa') */
new HtmlPwaPlugin(
{
name: 'project'
}
),
/* config.plugin('preload') */
new PreloadPlugin(
{
rel: 'preload',
include: 'initial',
fileBlacklist: [
/\.map$/,
/hot-update\.js$/
]
}
),
/* config.plugin('prefetch') */
new PreloadPlugin(
{
rel: 'prefetch',
include: 'asyncChunks'
}
),
/* config.plugin('copy') */
new CopyPlugin(
[
{
from: '/Users/me/Public/project/public',
to: '/Users/me/Public/project/dist',
toType: 'dir',
ignore: [
'.DS_Store',
{
glob: 'index.html',
matchBase: false
}
]
}
]
),
/* config.plugin('fork-ts-checker') */
new ForkTsCheckerWebpackPlugin(
{
vue: true,
tslint: false,
formatter: 'codeframe',
checkSyntacticErrors: false
}
),
{
definitions: {
'process.env': {
PACKAGE_VERSION: '"2.0.0"',
PACKAGE_NAME: '"project"'
}
}
}
],
entry: {
app: [
'./src/main.ts'
]
}
}
在我的代码中,我将自述文件中的演示附加到我想使用的界面(这是在 .ts 文件中,而不是 .vue 文件中,所以我真的有一半希望它能工作):
import { keys } from "ts-transformer-keys";
export interface FirebaseUser {
uid: string;
displayName?: string;
email?: string;
phoneNumber?: string;
emailVerified: boolean;
isAnonymous?: boolean;
}
const keysOfProps = keys<FirebaseUser>();
console.log({ keysOfProps });
这应该 simplify/reduce 像下面这样的工厂方法的债务:
export function factoryFirebaseUser(
data = <Partial<FirebaseUser>>{}
): FirebaseUser {
if (!data.hasOwnProperty("uid")) {
data.uid = undefined;
}
//...
return data as FirebaseUser;
}
但是当我 运行 npm run serve
我得到: Uncaught ReferenceError: keys is not defined
.. 你能帮我找出我还需要添加它的地方吗?
我想知道加载程序配置中所需的 transpileOnly: true,
选项是否是罪魁祸首?我相信这是为了让 babel 单独配置。
是的,添加 transpileOnly: true 确实有效。我打开了一份错误报告,询问有关这是否安全的详细信息,并在官方不和谐服务器上进行了调查:tl-dr 没有活跃的人知道。但至少它有效。
编辑:
现在我觉得自己像个白痴...从昨天晚上开始我就一直在做这件事。今天我意识到我可以测试将 transpileOnly 解析为 false:
chainWebpack: config => {
const getCustomTransformers = program => ({
before: [keysTransformer(program)]
});
const transpileOnly = false;
["ts", "tsx"].forEach(rule => {
config.module
.rule(rule)
.use("ts-loader")
.loader("ts-loader")
.tap(options => Object.assign(options, { getCustomTransformers, transpileOnly }));
});
},
而且..这确实有效。我在控制台中看到了我的界面键。我现在唯一的问题是——这样做会破坏什么?如果我这样做不安全,还有其他更好的方法吗?
来源:
此刻,我的怀疑(从最后一段)是 ts-loader 的 transpileOnly: true,
选项与 transformers 不兼容...如果是这样,有什么办法吗?只是对我的想法的确认或否定就会非常棒。有问题的变压器是 Kenji Imamula 的 ts-transformer-keys
我认为你需要熟悉 webpack 和 typescript,才能让它工作。如果你像我一样,专业地使用它但不涉及核心功能,你可能会喜欢这个变形金刚入门:how to write a TypeScript transform plugin
我在 wepack 方面非常有能力,所以我希望它能正常工作。但是,我是第一次使用 vue 3,webpack 是..不同的。你使用 vue.config.js 来设置一个块来使用 webpack-merge 或 webpack-chain 修改 webpack 配置。因为我想改变 ts 加载器(我假设),我使用了 chain.. 我还做了一些其他配置更改,所以我的 vue.config.ts 看起来像这样:
const PackageVars = require('./package-vars.webpack-plugin.js')
const keysTransformer = require('ts-transformer-keys/transformer').default
module.exports = {
configureWebpack: {
plugins: [PackageVars]
},
chainWebpack: config => {
const getCustomTransformers = program => ({
before: [keysTransformer(program)]
})
;['ts', 'tsx'].forEach(rule => {
config.module
.rule(rule)
.use('ts-loader')
.loader('ts-loader')
.tap(options => Object.assign(options, { getCustomTransformers }))
})
},
pluginOptions: {
i18n: {
locale: 'en',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: true
}
},
css: {
loaderOptions: {
sass: {
prependData: `@import "@/styles/global.scss";`
}
}
}
}
并生成一个 webpack.config.js(据 vue inspect 报告,这是缩写,主要是删除 css 相关的编译,因为 Whosebug 中的字符限制):
{
mode: 'development',
context: '/Users/me/Public/project',
node: {
setImmediate: false,
process: 'mock',
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
//...
resolveLoader: {
modules: [
'/Users/me/Public/project/node_modules/@vue/cli-plugin-typescript/node_modules',
'/Users/me/Public/project/node_modules/@vue/cli-plugin-babel/node_modules',
'node_modules',
'/Users/me/Public/project/node_modules',
'/Users/me/Public/project/node_modules/@vue/cli-service/node_modules'
]
},
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
rules: [
/* config.module.rule('vue') */
{
test: /\.vue$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/vue-loader',
cacheIdentifier: '1fc0539f'
}
},
{
loader: '/Users/me/Public/project/node_modules/vue-loader/lib/index.js',
options: {
compilerOptions: {
whitespace: 'condense'
},
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/vue-loader',
cacheIdentifier: '1fc0539f'
}
}
]
},
//...
/* config.module.rule('js') */
{
test: /\.m?jsx?$/,
exclude: [
function () { /* omitted long function */ }
],
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/babel-loader',
cacheIdentifier: '0fff5c38'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
}
]
},
/* config.module.rule('eslint') */
{
enforce: 'pre',
test: /\.(vue|(j|t)sx?)$/,
exclude: [
/node_modules/,
'/Users/me/Public/project/node_modules/@vue/cli-service/lib'
],
use: [
{
loader: '/Users/me/Public/project/node_modules/eslint-loader/index.js',
options: {
extensions: [
'.js',
'.jsx',
'.vue',
'.ts',
'.tsx'
],
cache: true,
cacheIdentifier: '5749dfb1',
emitWarning: false,
emitError: false,
eslintPath: '/Users/me/Public/project/node_modules/eslint',
formatter: function () { /* omitted long function */ }
}
}
]
},
/* config.module.rule('ts') */
{
test: /\.ts$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/ts-loader',
cacheIdentifier: 'b1785fd2'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: [
'\.vue$'
],
happyPackMode: false,
getCustomTransformers: program => ({
before: [keysTransformer(program)]
})
}
}
]
},
/* config.module.rule('tsx') */
{
test: /\.tsx$/,
use: [
{
loader: '/Users/me/Public/project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/Users/me/Public/project/node_modules/.cache/ts-loader',
cacheIdentifier: 'b1785fd2'
}
},
{
loader: '/Users/me/Public/project/node_modules/babel-loader/lib/index.js'
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
happyPackMode: false,
appendTsxSuffixTo: [
'\.vue$'
],
getCustomTransformers: program => ({
before: [keysTransformer(program)]
})
}
}
]
},
/* config.module.rule('i18n') */
{
resourceQuery: /blockType=i18n/,
type: 'javascript/auto',
use: [
{
loader: '@kazupon/vue-i18n-loader'
}
]
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\/]node_modules[\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
},
minimizer: [
{
options: {
test: /\.m?js(\?.*)?$/i,
chunkFilter: () => true,
warningsFilter: () => true,
extractComments: false,
sourceMap: true,
cache: true,
cacheKeys: defaultCacheKeys => defaultCacheKeys,
parallel: true,
include: undefined,
exclude: undefined,
minify: undefined,
terserOptions: {
compress: {
arrows: false,
collapse_vars: false,
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
booleans: true,
if_return: true,
sequences: true,
unused: true,
conditionals: true,
dead_code: true,
evaluate: true
},
mangle: {
safari10: true
}
}
}
}
]
},
plugins: [
/* config.plugin('vue-loader') */
new VueLoaderPlugin(),
/* config.plugin('define') */
new DefinePlugin(
{
'process.env': {
NODE_ENV: '"development"',
VUE_APP_I18N_LOCALE: '"en"',
VUE_APP_I18N_FALLBACK_LOCALE: '"en"',
BASE_URL: '"/"'
}
}
),
/* config.plugin('case-sensitive-paths') */
new CaseSensitivePathsPlugin(),
/* config.plugin('friendly-errors') */
new FriendlyErrorsWebpackPlugin(
{
additionalTransformers: [
function () { /* omitted long function */ }
],
additionalFormatters: [
function () { /* omitted long function */ }
]
}
),
/* config.plugin('html') */
new HtmlWebpackPlugin(
{
templateParameters: function () { /* omitted long function */ },
template: '/Users/me/Public/project/public/index.html'
}
),
/* config.plugin('pwa') */
new HtmlPwaPlugin(
{
name: 'project'
}
),
/* config.plugin('preload') */
new PreloadPlugin(
{
rel: 'preload',
include: 'initial',
fileBlacklist: [
/\.map$/,
/hot-update\.js$/
]
}
),
/* config.plugin('prefetch') */
new PreloadPlugin(
{
rel: 'prefetch',
include: 'asyncChunks'
}
),
/* config.plugin('copy') */
new CopyPlugin(
[
{
from: '/Users/me/Public/project/public',
to: '/Users/me/Public/project/dist',
toType: 'dir',
ignore: [
'.DS_Store',
{
glob: 'index.html',
matchBase: false
}
]
}
]
),
/* config.plugin('fork-ts-checker') */
new ForkTsCheckerWebpackPlugin(
{
vue: true,
tslint: false,
formatter: 'codeframe',
checkSyntacticErrors: false
}
),
{
definitions: {
'process.env': {
PACKAGE_VERSION: '"2.0.0"',
PACKAGE_NAME: '"project"'
}
}
}
],
entry: {
app: [
'./src/main.ts'
]
}
}
在我的代码中,我将自述文件中的演示附加到我想使用的界面(这是在 .ts 文件中,而不是 .vue 文件中,所以我真的有一半希望它能工作):
import { keys } from "ts-transformer-keys";
export interface FirebaseUser {
uid: string;
displayName?: string;
email?: string;
phoneNumber?: string;
emailVerified: boolean;
isAnonymous?: boolean;
}
const keysOfProps = keys<FirebaseUser>();
console.log({ keysOfProps });
这应该 simplify/reduce 像下面这样的工厂方法的债务:
export function factoryFirebaseUser(
data = <Partial<FirebaseUser>>{}
): FirebaseUser {
if (!data.hasOwnProperty("uid")) {
data.uid = undefined;
}
//...
return data as FirebaseUser;
}
但是当我 运行 npm run serve
我得到: Uncaught ReferenceError: keys is not defined
.. 你能帮我找出我还需要添加它的地方吗?
我想知道加载程序配置中所需的 transpileOnly: true,
选项是否是罪魁祸首?我相信这是为了让 babel 单独配置。
是的,添加 transpileOnly: true 确实有效。我打开了一份错误报告,询问有关这是否安全的详细信息,并在官方不和谐服务器上进行了调查:tl-dr 没有活跃的人知道。但至少它有效。