侧边栏壁纸
博主头像
M酷博主等级

一帆风顺 ⛵️⛵️⛵️

  • 累计撰写 45 篇文章
  • 累计创建 40 个标签
  • 累计收到 464 条评论

目 录CONTENT

文章目录

Vue2 + Webpack4 + TS 改造小记

M酷
2021-12-22 / 3 评论 / 17 点赞 / 5,616 阅读 / 4,188 字 / 正在检测是否收录...
广告 广告

1、vue 文件中的 script 标签加了 lang="ts" 后无法成功引入

[typescript] ts-loader! Module build failed: Error: Could not find source file:

  • 原因:主要是由于 vue 文件首先被 vue-loader 识别,但 vue-loader 内部并没有对内部的 ts 进行处理,所以无法识别 script 中的代码。
  • 解决:只需要在 vue-loaderoptions 中加入一个 ts-loader 就可以了。
{
  test: /\.vue$/,
  loader: "vue-loader",
  options: {
    loaders: {
      less: [
        "vue-style-loader",
        "css-loader",
        "less-loader?indentedSyntax",
      ],
      ts: [
        {
          loader: "ts-loader",
          options: {
            appendTsSuffixTo: [/\.vue$/],
          },
        },
      ],
    },
  },
}

2、ts 文件中无法识别 vue 文件和 window 自定义属性

  • 原因:由于 TypeScript  默认并不支持  *.vue  后缀的文件,所以在  vue  项目中引入的时候需要创建一个 vue-shim.d.ts  文件,放在项目对应使用目录下(也可在 tsconfig.json 中的 include 配置扫描路径),例如  src/vue-shim.d.ts
  • 解决:
// 用于支持 ts 引入 vue文件
declare module "*.vue" {
  import Vue from "vue";
  export default Vue;
}

// 用于支持 this.$router 这种形式的调用
declare module "vue/types/vue" {
  interface Vue {
    $myProperty: string;
  }
}

// Window 自定义属性,当然也可以直接 (window as any).ethereum 这样使用
declare global {
  interface Window {
    isSupportWebp: boolean
    web3: any
    ethereum: any
  }
}

// 文件尾部导出一个空对象,保证定义的类型生效
export {}

注意:
注意即使此声明文件不需要导出任何东西,也需要导出一个空对象(或者文件中包含 import 语句也可以),用来告诉编译器这是一个模块的声明文件,否则类型定义无效。

3、错误 “SyntaxError: Unexpected token } in JSON at position”

  • 原因:主要是因为 json 文件中的格式有问题,导致后面使用 JSON.parse 解析时报错。
  • 解决:复制 json 内容到 FE helper 中检查并修改后再试试。

4、使用 postcss 时样式中的注释报错

  • 原因:主要是因为 loader 加载顺序不对导致的(从右往左解析)。
  • 解决:比如说使用的是 less,只需要调整 loader 的顺序为 "vue-style-loader","css-loader", "postcss-loader"
    即可。

5、this.$refs 无法识别

  • 原因:typescript 无法识别出 this.$refs.xx 是否含有 xx 方法。

  • 解决:方法比较多:

    • 一劳永逸,直接声明为 any
    const myRef: any = this.$refs.myModal;
    
    • 类型断言
    (this.$refs.myModal as Vue & {resetFields:Function}).resetFields();
    
    • 接口继承
    • 直接引入 vue-class-component,更直观的定义 $refs 的类型
    <template>
      <input ref="input" />
    </template>
    
    <script lang="ts">
      import Vue from "vue";
      import Component from "vue-class-component";
    
      @Component
      export default class InputFocus extends Vue {
        // annotate refs type.
        // The symbol `!` (definite assignment assertion)
        // is needed to get rid of compilation error.
        $refs!: {
          input: HTMLInputElement;
        };
    
        mounted() {
          // Use `input` ref without type cast.
          this.$refs.input.focus();
        }
      }
    </script>
    

6、vue-class-componentvue-property-decorator 支持

  • vue-class-componentVue 组件进行了一层封装,让 Vue 组件语法在结合了 TypeScript 语法之后更加扁平化,vue-property-decorator 是在 vue-class-component 上增强了更多的结合 Vue 特性的装饰器。
  • 这 2 个包可以让我们更优雅的书写代码。
npm i -D vue-class-component vue-property-decorator

7、运行测试用例时 vue-jest 报错

Babel bug: .inputSourceMap must be a boolean, object, or undefined & filename is undefined

  • 原因:由于当前安装的 babel 和引用的 babel-core 版本不匹配导致的,babel6 对应 babel-corebabel7 对应 @/babel-core
  • 解决:通过搜索和查阅文档,发现已在指定版本修复,安装对应版本即可修复。

8、html-webpack-plugin 配置 template 无效

一直使用根目录下的 index.html,且其他配置也无效

  • 原因:主要是由于 webpack 配置中的 publicPath 配置的问题,使用时需要格外注意。
  • 解决:通过判断 process.env.NODE_ENV 分别设置开发和生产环境的资源路径。
output: {
   path: pathResolve("dist"),
   publicPath: process.env.NODE_ENV === "production" ? "." : "/",
   filename: "build.js?[hash:5]",
}

9、npm 包版本号导致的各种报错

  • 原因:由于不同的 npm 包适配的环境不一样,使用时需要格外注意。
  • 解决:通过搜索和查阅文档,找到可以正常工作的匹配版本,尽量避免过高或过低的版本。

10、TS 中 any 和 unknown 的区别?

  • unknowntop type ,任何类型都是它的 subtype,也就是说它可以被赋为任何值,但只能赋值给 anyunknow 类型的变量。
  • anytop type + bottom type ,任何类型都是它的 subtype,它也是任何类型的 subtype,也就是说 any 基本上就是关闭了类型检查。

参考 Typescript 最佳实践

11、Plugin 与 Preset 执行顺序

preset 相当于包含一个或多个 plugin,可以避免手动安装多个 plugin,提高效率,减少出错几率,比如 @babel/preset-env
可以同时使用多个 PluginPreset,此时它们的执行顺序非常重要。

  • 先执行完所有 Plugin,再执行 Preset
  • 多个 Plugin,按照声明次序顺序执行
  • 多个 Preset,按照声明次序逆序执行

12、Jest did not exit one second after the test run has completed

  • 原因:使用 jest 执行完测试用例后,提示 jest 没有自动退出,猜想应该是有异步任务没结束导致的。
  • 解决:改写相关代码,让任务能终止
import { throttle } from "./throttle";
import { timer } from "rxjs";

describe("testing", () => {
  it("test-throttle", (done) => {
    let count = 0;
    function __addCount() {
      count += 1;
    }
    const addCount = throttle(__addCount, 100);
    let source = timer(0, 10).subscribe((i: number) => {
      if (i === 100) {
        expect(count).toBe(12);
        done();
        source.unsubscribe(); // 这里及时停止计时器即可
      } else {
        addCount();
      }
    });
  });
});

13、mac 下提示 permission denied

  • 原因:没有执行权限

  • 解决:

    • chmod 是权限管理命令 change the permissions mode of a file 的缩写。
    • u 代表所有者,x 代表执行权限,+ 表示增加权限。
    • chmod u+x file.sh 就表示对当前目录下的 file.sh 文件的所有者增加可执行权限。

14、解决 typescript Cannot redeclare block-scoped variable

  • 原因:没有模块化,会有变量污染的问题
  • 解决:只需要在文件末尾加上 export {}

15、Could not find a declaration file for module ‘xxx’. ‘xxx’ implicitly has an 'any’type.

  • 场景:TS 项目中,通过 import 引入 js 文件提示找不到 module
  • 原因:没有对 js 定义模块
  • 解决:只需要在 shim.d.ts 中添加一行 declare module "\*.js";
17
广告 广告

评论区