Skip to content

Commit

Permalink
feat(utils): 新增 getCurrentScript 返回当前正在运行的脚本所属的 <script> 元素
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Jul 29, 2021
1 parent ce2ae2c commit d2a93d8
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/utils/getCurrentScript.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getCurrentScript } from './getCurrentScript'

describe('getCurrentScript', () => {
test('表现正常', () => {
expect(getCurrentScript()).toBeNull()
})
})
86 changes: 86 additions & 0 deletions src/utils/getCurrentScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* eslint-disable prefer-const */
// ref: https://github.com/sodatea/get-current-script/blob/main/index.js

/**
* 返回当前正在运行的脚本所属的 `<script>` 元素。有两点限制:
*
* - 只在脚本被解析后首次运行时有效;
* - 如果当前正在执行的代码是被其他代码作为回调函数或者事件处理函数调用的,会返回 `null`。
*/
export function getCurrentScript(): HTMLScriptElement | null {
const descriptor = Object.getOwnPropertyDescriptor(document, 'currentScript')
// for chrome
if (!descriptor && 'currentScript' in document && document.currentScript) {
return document.currentScript as any
}

// for other browsers with native support for currentScript
if (
descriptor &&
descriptor.get !== getCurrentScript &&
document.currentScript
) {
return document.currentScript as any
}

// IE 8-10 support script readyState
// IE 11+ & Firefox support stack trace
try {
throw new Error()
} catch (err) {
// Find the second match for the "at" string to get file src url from stack.
let ieStackRegExp = /.*at [^(]*\((.*):(.+):(.+)\)$/gi,
ffStackRegExp = /@([^@]*):(\d+):(\d+)\s*$/gi,
stackDetails =
ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack),
scriptLocation = (stackDetails && stackDetails[1]) || false,
line = (stackDetails && stackDetails[2]) || false,
currentLocation = document.location.href.replace(
document.location.hash,
'',
),
pageSource,
inlineScriptSourceRegExp,
inlineScriptSource,
scripts = document.getElementsByTagName('script') // Live NodeList collection

// try to find the matching external script first
for (let i = 0; i < scripts.length; i++) {
// If ready state is interactive, return the script tag
if ((scripts[i] as any).readyState === 'interactive') {
return scripts[i]
}

// If src matches, return the script tag
if (scripts[i].src === scriptLocation) {
return scripts[i]
}
}

// if not found, the current script is likely inline
if (scriptLocation === currentLocation) {
pageSource = document.documentElement.outerHTML
inlineScriptSourceRegExp = new RegExp(
`(?:[^\\n]+?\\n){0,${
(line as any) - 2
}}[^<]*<script>([\\d\\D]*?)<\\/script>[\\d\\D]*`,
'i',
)
inlineScriptSource = pageSource
.replace(inlineScriptSourceRegExp, '$1')
.trim()

// find the matching inline script
for (let i = 0; i < scripts.length; i++) {
if (
scripts[i].innerHTML &&
scripts[i].innerHTML.trim() === inlineScriptSource
)
return scripts[i]
}
}

// If no match, return null
return null
}
}
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './dedent'
export * from './EventBus'
export * from './formatBytes'
export * from './formatNumber'
export * from './getCurrentScript'
export * from './getEnvironment'
export * from './getWechatPublicAccountQrcodeUrl'
export * from './ii'
Expand Down

0 comments on commit d2a93d8

Please sign in to comment.