4
2

More than 3 years have passed since last update.

Optional Chaining のエラーをもう一度整理

Posted at

前回の反省点として、Optional Chainingに問題をすり替えてしまって、結果、混沌としてしまったです。
よくよく考えれば、ts-loaderもbabelも Optional Chaining はサポートしているのであって、こいつらはローダー君は指定されたバージョンのjavascriptへ変換するのがお仕事です。
つまり、ここが原因でエラーがどうとか話しすと話が混乱するのですな。

ということで、もう一度出力されているエラーを見てみる。

storybook をビルドして発生するエラー

ERROR in ./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts& (./node_modules/vue-docgen-loader/lib??ref--12!./node_modules/ts-loader??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&) 8:36
Module parse failed: Unexpected token (8:36)
File was processed with these loaders:
 * ./node_modules/vue-docgen-loader/lib/index.js
 * ./node_modules/vue-docgen-loader/lib/index.js
 * ./node_modules/ts-loader/index.js
 * ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|         const canvas = ref();
|         watch(canvas, () => {
>             const gl = canvas.value?.getContext("webgl");
|             if (gl) {
|                 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 @ ./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts& 1:0-236 1:252-255 1:257-490 1:257-490
 @ ./src/components/_sandbox/WebGL.vue
 @ ./src/components/_sandbox/WebGL.stories.ts
 @ ./src sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./.storybook/generated-stories-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/vue/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addParameter.js-generated-other-entry.js ./node_modules/@storybook/addon-knobs/dist/preset/addDecorator.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined

Module parse failed: Unexpected token (8:36) ということは、どうやら期待されていないトークンに遭遇したらしい。
次に、const gl = canvas.value?.getContext("webgl");という、ソースコードの場所を明示してくれている。
で、webpackというヤツはルールに従ってloaderがバケツリレーをしながら javascript に置き換えるので、「誰が音を上げた」というのが問題になる。
スタックトレース的なものが表示されているが、コイツが昇順なのか降順なのか、想像はできるが確定できないので、少し手を変えてみる。

エラーを表示している場所を探す

スクリプト系の言語なら、エラーを表示しているコードを探せるかも、って事で You may need an additional loader to handle the result of these loaders. を検索してみると webpack/lib/ModuleParseError.js で検索されていることがわかる。
こいう時のコツとしては、runtimeのエラー文字列っぽくないものを探すのがコツ。

で、このエラー文字列は ModuleParseError の constructor() で使っている(生成している)ことが分かる。
じゃぁ、どこから呼び出されているのかを調べたくなるので、console.trace()を追加してみて、再度ビルドしてみる。

Trace
    at new ModuleParseError (/Users/teru/git/uilib/node_modules/webpack/lib/ModuleParseError.js:27:12)
    at handleParseError (/Users/teru/git/uilib/node_modules/webpack/lib/NormalModule.js:469:19)
    at /Users/teru/git/uilib/node_modules/webpack/lib/NormalModule.js:503:5
    at /Users/teru/git/uilib/node_modules/webpack/lib/NormalModule.js:358:12
    at /Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:373:3
    at iterateNormalLoaders (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
    at iterateNormalLoaders (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
    at /Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:236:3
    at context.callback (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:111:13)
    at Object.module.exports (/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js:28:5)
    at LOADER_EXECUTION (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:119:14)
    at runSyncOrAsync (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:120:4)
    at iterateNormalLoaders (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:232:2)
    at iterateNormalLoaders (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
    at /Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:236:3
    at context.callback (/Users/teru/git/uilib/node_modules/loader-runner/lib/LoaderRunner.js:111:13)

ふむ。。。 あ〜 vue-docgen-loader が居るな。。。
こいつ何なんだろうか。。。
まぁ、それは後で調べるにして、もうちょい情報が欲しいから、この constructor() に渡されるパラメータをダンプしてみよう。
定義はこんな感じModuleParseError(module, source, err, loaders)だったんで。。。

module

/* NormalModule */ {
  dependencies: [],
  blocks: [],
  variables: [],
  type: 'javascript/auto',
  context: '/Users/teru/git/uilib/src/components/_sandbox',
  debugId: 1422,
  hash: undefined,
  renderedHash: undefined,
  resolveOptions: {},
  factoryMeta: {},
  warnings: [],
  errors: [],
  buildMeta: { tsLoaderFileVersion: 1 },
  buildInfo: {
    cacheable: true,
    fileDependencies: Set { '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue' },
    contextDependencies: Set {},
    assets: undefined,
    assetsInfo: undefined
  },
  reasons: [
    ModuleReason {
      module: [NormalModule],
      dependency: [HarmonyImportSideEffectDependency],
      explanation: undefined,
      _chunks: null
    },
    ModuleReason {
      module: [NormalModule],
      dependency: [HarmonyImportSpecifierDependency],
      explanation: undefined,
      _chunks: null
    },
    ModuleReason {
      module: [NormalModule],
      dependency: [HarmonyImportSideEffectDependency],
      explanation: undefined,
      _chunks: null
    },
    ModuleReason {
      module: [NormalModule],
      dependency: [HarmonyExportImportedSpecifierDependency],
      explanation: undefined,
      _chunks: null
    }
  ],
  _chunks: SortableSet [Set] {
    _sortFn: [Function: sortById],
    _lastActiveSortFn: null,
    _cache: undefined,
    _cacheOrderIndependent: undefined
  },
  id: null,
  index: null,
  index2: null,
  depth: null,
  issuer: NormalModule {
    dependencies: [
      [HarmonyCompatibilityDependency],
      [HarmonyInitDependency],
      [ConstDependency],
      [HarmonyImportSideEffectDependency],
      [HarmonyExportHeaderDependency],
      [HarmonyExportExpressionDependency],
      [HarmonyImportSpecifierDependency],
      [ConstDependency],
      [HarmonyImportSideEffectDependency],
      [HarmonyExportImportedSpecifierDependency]
    ],
    blocks: [],
    variables: [],
    type: 'javascript/auto',
    context: '/Users/teru/git/uilib/src/components/_sandbox',
    debugId: 1421,
    hash: undefined,
    renderedHash: undefined,
    resolveOptions: {},
    factoryMeta: {},
    warnings: [],
    errors: [],
    buildMeta: { exportsType: 'namespace' },
    buildInfo: {
      cacheable: true,
      fileDependencies: Set {},
      contextDependencies: Set {},
      assets: undefined,
      assetsInfo: undefined,
      strict: true,
      exportsArgument: '__webpack_exports__'
    },
    reasons: [ [ModuleReason], [ModuleReason], [ModuleReason], [ModuleReason] ],
    _chunks: SortableSet [Set] {
      _sortFn: [Function: sortById],
      _lastActiveSortFn: null,
      _cache: undefined,
      _cacheOrderIndependent: undefined
    },
    id: null,
    index: null,
    index2: null,
    depth: null,
    issuer: NormalModule {
      dependencies: [Array],
      blocks: [],
      variables: [],
      type: 'javascript/auto',
      context: '/Users/teru/git/uilib/src/components/_sandbox',
      debugId: 1217,
      hash: undefined,
      renderedHash: undefined,
      resolveOptions: {},
      factoryMeta: {},
      warnings: [],
      errors: [],
      buildMeta: [Object],
      buildInfo: [Object],
      reasons: [Array],
      _chunks: [SortableSet [Set]],
      id: null,
      index: null,
      index2: null,
      depth: null,
      issuer: [NormalModule],
      profile: undefined,
      prefetched: false,
      built: true,
      used: null,
      usedExports: null,
      optimizationBailout: [],
      _rewriteChunkInReasons: undefined,
      useSourceMap: true,
      _source: [OriginalSource],
      request: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue',
      userRequest: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue',
      rawRequest: './WebGL.vue',
      binary: false,
      parser: [Parser],
      generator: JavascriptGenerator {},
      resource: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue',
      matchResource: undefined,
      loaders: [Array],
      error: null,
      _sourceSize: null,
      _buildHash: 'd57de076f7ac96f23ab1c0ce9011f9e8',
      buildTimestamp: 1613107043574,
      _cachedSources: Map {},
      lineToLine: false,
      _lastSuccessfulBuildMeta: [Object],
      _ast: null
    },
    profile: undefined,
    prefetched: false,
    built: true,
    used: null,
    usedExports: null,
    optimizationBailout: [],
    _rewriteChunkInReasons: undefined,
    useSourceMap: true,
    _source: OriginalSource {
      _value: 'import mod from "-!../../../node_modules/vue-docgen-loader/lib/index.js??ref--12!../../../node_modules/ts-loader/index.js??ref--4-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./WebGL.vue?vue&type=script&lang=ts&"; export default mod; export * from "-!../../../node_modules/vue-docgen-loader/lib/index.js??ref--12!../../../node_modules/ts-loader/index.js??ref--4-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./WebGL.vue?vue&type=script&lang=ts&"',
      _name: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/vue-loader/lib/loaders/pitcher.js??ref--4!/Users/teru/git/uilib/node_modules/ts-loader/index.js??ref--4-0!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&'
    },
    request: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/vue-loader/lib/loaders/pitcher.js??ref--4!/Users/teru/git/uilib/node_modules/ts-loader/index.js??ref--4-0!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
    userRequest: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
    rawRequest: './WebGL.vue?vue&type=script&lang=ts&',
    binary: false,
    parser: Parser {
      _pluginCompat: [SyncBailHook],
      hooks: [Object],
      options: {},
      sourceType: 'auto',
      scope: undefined,
      state: undefined,
      comments: undefined
    },
    generator: JavascriptGenerator {},
    resource: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
    matchResource: undefined,
    loaders: [ [Object], [Object], [Object], [Object] ],
    error: null,
    _sourceSize: null,
    _buildHash: '76f6da385d20205e0eefa56e89ec04d1',
    buildTimestamp: 1613107043951,
    _cachedSources: Map {},
    lineToLine: false,
    _lastSuccessfulBuildMeta: { exportsType: 'namespace' },
    _ast: null
  },
  profile: undefined,
  prefetched: false,
  built: true,
  used: null,
  usedExports: null,
  optimizationBailout: [],
  _rewriteChunkInReasons: undefined,
  useSourceMap: true,
  _source: SourceMapSource {
    _value: 'import { defineComponent, ref, watch } from "@vue/composition-api";\n' +
      'export default defineComponent({\n' +
      '    name: "WebGL",\n' +
      '    props: {},\n' +
      '    setup: (props, ctx) => {\n' +
      '        const canvas = ref();\n' +
      '        watch(canvas, () => {\n' +
      '            const gl = canvas.value?.getContext("webgl");\n' +
      '            if (gl) {\n' +
      '                gl.clearColor(0.0, 0.0, 0.0, 1.0);\n' +
      '                gl.clear(gl.COLOR_BUFFER_BIT);\n' +
      '            }\n' +
      '        });\n' +
      '        return { canvas };\n' +
      '    }\n' +
      '});\n',
    _name: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/ts-loader/index.js??ref--4-0!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
    _sourceMap: {
      version: 3,
      file: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue.ts',
      sourceRoot: '',
      sources: [Array],
      names: [],
      mappings: 'AAKA,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEnE,eAAe,eAAe,CAAC;IAC7B,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,GAAG,EAAqB,CAAC;QACxC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE;YACjB,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,EAAE,EAAE;gBACN,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBAClC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;aAC/B;QACH,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF,CAAC,CAAC',
      sourcesContent: [Array]
    },
    _originalSource: undefined,
    _innerSourceMap: undefined,
    _removeOriginalSource: undefined
  },
  request: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/ts-loader/index.js??ref--4-0!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
  userRequest: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js??ref--12!/Users/teru/git/uilib/node_modules/ts-loader/index.js??ref--4-0!/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js??vue-loader-options!/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
  rawRequest: '-!../../../node_modules/vue-docgen-loader/lib/index.js??ref--12!../../../node_modules/ts-loader/index.js??ref--4-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./WebGL.vue?vue&type=script&lang=ts&',
  binary: false,
  parser: Parser {
    _pluginCompat: SyncBailHook {
      _args: [Array],
      taps: [Array],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    hooks: {
      evaluateTypeof: [HookMap],
      evaluate: [HookMap],
      evaluateIdentifier: [HookMap],
      evaluateDefinedIdentifier: [HookMap],
      evaluateCallExpressionMember: [HookMap],
      statement: [SyncBailHook],
      statementIf: [SyncBailHook],
      label: [HookMap],
      import: [SyncBailHook],
      importSpecifier: [SyncBailHook],
      export: [SyncBailHook],
      exportImport: [SyncBailHook],
      exportDeclaration: [SyncBailHook],
      exportExpression: [SyncBailHook],
      exportSpecifier: [SyncBailHook],
      exportImportSpecifier: [SyncBailHook],
      varDeclaration: [HookMap],
      varDeclarationLet: [HookMap],
      varDeclarationConst: [HookMap],
      varDeclarationVar: [HookMap],
      canRename: [HookMap],
      rename: [HookMap],
      assigned: [HookMap],
      assign: [HookMap],
      typeof: [HookMap],
      importCall: [SyncBailHook],
      call: [HookMap],
      callAnyMember: [HookMap],
      new: [HookMap],
      expression: [HookMap],
      expressionAnyMember: [HookMap],
      expressionConditionalOperator: [SyncBailHook],
      expressionLogicalOperator: [SyncBailHook],
      program: [SyncBailHook],
      hotAcceptCallback: [SyncBailHook],
      hotAcceptWithoutCallback: [SyncBailHook]
    },
    options: {},
    sourceType: 'auto',
    scope: undefined,
    state: undefined,
    comments: undefined
  },
  generator: JavascriptGenerator {},
  resource: '/Users/teru/git/uilib/src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&',
  matchResource: undefined,
  loaders: [
    {
      options: [Object],
      ident: 'ref--12',
      loader: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js'
    },
    {
      loader: '/Users/teru/git/uilib/node_modules/vue-docgen-loader/lib/index.js',
      options: [Object],
      ident: 'ref--12'
    },
    {
      loader: '/Users/teru/git/uilib/node_modules/ts-loader/index.js',
      options: [Object],
      ident: 'ref--4-0'
    },
    {
      loader: '/Users/teru/git/uilib/node_modules/vue-loader/lib/index.js',
      options: {},
      ident: 'vue-loader-options'
    }
  ],
  error: null,
  _sourceSize: null,
  _buildHash: '',
  buildTimestamp: 1613107043952,
  _cachedSources: Map {},
  lineToLine: false,
  _lastSuccessfulBuildMeta: {},
  _ast: null
}

source

import { defineComponent, ref, watch } from "@vue/composition-api";
export default defineComponent({
    name: "WebGL",
    props: {},
    setup: (props, ctx) => {
        const canvas = ref();
        watch(canvas, () => {
            const gl = canvas.value?.getContext("webgl");
            if (gl) {
                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                gl.clear(gl.COLOR_BUFFER_BIT);
            }
        });
        return { canvas };
    }
});

err

SyntaxError: Unexpected token (8:36)
    at Parser.pp$4.raise (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2825:15)
    at Parser.pp.unexpected (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:689:10)
    at Parser.pp$3.parseExprAtom (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2270:12)
    at Parser.pp$3.parseExprSubscripts (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2089:21)
    at Parser.pp$3.parseMaybeUnary (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2066:19)
    at Parser.pp$3.parseExprOps (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2010:21)
    at Parser.pp$3.parseMaybeConditional (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1993:21)
    at Parser.pp$3.parseMaybeAssign (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1968:21)
    at Parser.pp$3.parseMaybeConditional (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1998:30)
    at Parser.pp$3.parseMaybeAssign (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1968:21)
    at Parser.pp$1.parseVar (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1228:26)
    at Parser.pp$1.parseVarStatement (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1092:10)
    at Parser.pp$1.parseStatement (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:842:19)
    at Parser.pp$1.parseBlock (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:1161:23)
    at Parser.pp$3.parseFunctionBody (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2671:24)
    at Parser.pp$3.parseArrowExpression (/Users/teru/git/uilib/node_modules/acorn/dist/acorn.js:2634:10) {
  pos: 260,
  loc: Position { line: 8, column: 36 },
  raisedAt: 261
}

loaders

[
  './node_modules/vue-docgen-loader/lib/index.js',
  './node_modules/vue-docgen-loader/lib/index.js',
  './node_modules/ts-loader/index.js',
  './node_modules/vue-loader/lib/index.js'
]

ここにきて、ようやくエラーの根源を発見!(実は、当初のビルドで表示されているんだけどね)
acorn が例外投げてるっぽい。
で、acornって、何者だ?

あと、errのスタックトレースが acorn 内で終わっているので、そもそも、これ呼び出しているのは誰?って事で調べてみる。

エラーの根源

もう一度、整理すると。

  • ModuleParseError でエラーが構成されているが、これは発生したエラーを受け、表示用にエラーを構成しているもので、エラーそのものではない。
  • ModuleParseError を誰かが呼び出している。
  • エラーの発生は acorn で確定。

ということで、ModuleParseError って誰が呼び出しているのかを調べてみる。

ModuleParseError の生成箇所を追う

とりあえず、検索してみると NormalModule.js で生成していることが分かる。
そして、NormalModule.build() 内で、 doBuild() を呼び出し、ここのコールバックで生成している。
で、条件としては、 this.parser.parse() でエラーが発生した時、または、this.parser.parse()が例外を発生させた時のみ。
念の為、この2つのケースに console.log() を入れてみて確認してみると、catch節で ModuleParseError が生成されることを確認した。

acorn って何者?

で、javascriptのパーサーでした。
npm で週4千万ダウンロードされてる、神様的なライブラリですね。
いつもお世話になっているのに、知らなくてゴメンね。
で、この子は、文字列とパラメータを与えると、構文解析して、ESTree Specにくれるものみたいです。

つまり、この子が理解できないと例外を発生させたのですが、最新の acorn 8.0.5 は ECMA12までサポートしてます。
storybook が使っている acorn はというと。。。 storybook -> webpack -> acorn で 7.1.0 か。。。
どうなんだろう? これかな?

そういえば NormalModule って?

そうそう、エラー出しているのは NormalModule の this.parser.parse() だったっけ。
ところで、こいつの this.parser って何者なんだ?
acron にも parse() って関数あるんだけど、引数違うから、まだ途中に誰か居るな。

ということで、 NormalModule.parser は誰なのか追ってみる。

どうやら、this.parserに代入している箇所は、constructor() と updateCacheModule() だが、取り敢えず、何者かを知りたいので、constructor に絞って探してみる。
(あ〜、動的型付け言語は追いづれ〜〜〜)
試しに、 "new NormalModule" で検索してみると、NormalModuleFactory.js がヒットするので、何となくコレっぽい。

  let createdModule = this.hooks.createModule.call(result);
  if (!createdModule) {
    if (!result.request) {
      return callback(new Error("Empty dependency (no request)"));
    }

    createdModule = new NormalModule(result);
  }

が、こいつ、条件付きで new されるみたいで、hook とかいうヤツが生成する場合がある(どっちが多いんだか分からん)。

ちと、 NormalModule って、資料ないのかと調べてみる。

あれ? webpack 本家サイトで "NormalObject" が登場するのはここしかない。
NormalObject を生成するファクトリについては解説しているが。。。
https://webpack.js.org/api/normalmodulefactory-hooks/

何だ? 知ってて当然で、知らない人はお断り的なヤツなんか?
まぁ、実際はwebpackの内部クラスで、webpack作っている方々以外は触るもんじゃないんでしょう。
で、NormalModuleを置き換えるプラグイン的な切り口については解説してますな。
https://webpack.js.org/plugins/normal-module-replacement-plugin/

ここまでくると、デバッガで動かさないと分からん。。。
ひとます、置いといて。。。

え〜っと、何やってるんだっけ?(苦笑)

残りは vue-docgen-loader

こいつは、vue を解析して、propertyやらeventやらを抽出する便利なヤツです。
こいつが動くってことは、誰かが呼び出しているはずなので探してみると。。。。
@storybook/addon-docs の中で、webpackFilnal() 関数の中におりました。
まともに動かないのを覚悟で、 vue-docgen-loader を module.rules に追加している箇所をコメントアウトしてみると。

ERROR in ./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts& (./node_modules/ts-loader??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts&) 8:36
Module parse failed: Unexpected token (8:36)
File was processed with these loaders:
 * ./node_modules/ts-loader/index.js
 * ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|         const canvas = ref();
|         watch(canvas, () => {
>             const gl = canvas.value?.getContext("webgl");
|             if (gl) {
|                 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 @ ./src/components/_sandbox/WebGL.vue?vue&type=script&lang=ts& 1:0-174 1:190-193 1:195-366 1:195-366
 @ ./src/components/_sandbox/WebGL.vue
 @ ./src/components/_sandbox/WebGL.stories.ts
 @ ./src sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./.storybook/generated-stories-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/vue/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/addParameter.js-generated-other-entry.js ./node_modules/@storybook/addon-knobs/dist/preset/addDecorator.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined

まだエラー出てるけど、vue-docgen-loader がエラー出てるんじゃないのね。
で、更に、webpackの設定周りを追っていると、 iframe-webpack.config.js にぶちあたり、"generated-stories-entry.js" という、エラーで見かけた文字列を発見。

こりゃ、まだ続くな。。。

取り敢えず、これまでの解析結果は。。。

  • storybook で Optional Chaining を使うとエラーになる
  • tsconfig.json で target を ES6 にするとエラーはなくなる
  • エラーの発生に関連するものは。。。
    • acron(例外発生場所)
    • webpack の NormalModule.build() (エラーハンドリング場所)
    • vue-docgen-loader
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2