SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的`this`指向问题详解
    • SessionStorage踩坑记录:它真的能"只设置一次"吗?
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
  • es6

    • Promise
    • es6 模块导出方式全解析
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue 3 深度选择器:deep()完全指南
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • 使用 pnpm 构建 Monorepo 实战指南
    • pnpm 修改依赖源码打包报错
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧

JavaScript 中的 script 标签问题详解

1. script 标签的核心属性

type 属性

  • type="text/javascript":默认值,可省略

  • type="module":将脚本作为 ES6 模块处理,支持 import/export

  • type="application/json":包含 JSON 数据

  • type="application/ld+json":结构化数据

  • type="importmap":定义模块导入映射

加载控制属性

  • async:异步加载,加载完立即执行,不阻塞解析

  • defer:延迟执行,等 DOM 解析完成后按顺序执行

  • nomodule:在支持 ES 模块的浏览器中忽略此脚本

安全相关属性

  • integrity:子资源完整性检查

  • crossorigin:跨域资源共享设置

  • referrerpolicy:控制 HTTP 请求的 Referer 头

其他属性

  • src:外部脚本的 URL

  • charset:已废弃,使用 HTTP 头或 meta 标签

  • language:已废弃,使用 type 替代

2. 常见问题与解决方案

问题:Cannot use import statement outside a module

错误信息:

Uncaught SyntaxError: Cannot use import statement outside a module (at buriedLogic.js:1:1)

问题原因: 使用了 ES6 的 import/export 语法,但脚本没有被当作模块加载。

示例代码:

// buriedLogic.js
import Config from "./config.js";
import BuriedPoint from "./buriedPoint.js";
import AppJump from "./appJump.js";

class BuriedLogic {
  // 类定义...
}

解决方案:

  1. 方法一:在 HTML 中添加 type="module"属性(推荐)

    <script type="module" src="buriedLogic.js"></script>
  2. 方法二:不使用 ES6 模块语法,改为传统方式

    // 移除import语句
    // 使用自执行函数封装所有代码
    (function () {
      // 将所有代码放在这个作用域内
      // ...
    })();

为什么方法一有效:

  • 添加type="module"后,浏览器以 ES 模块规范解析脚本

  • 模块有自己的作用域,自动采用严格模式

  • 支持 import/export 语法

  • 模块默认延迟加载(类似 defer)

  • 每个模块只执行一次

3. 传统脚本与 ES 模块的区别

传统脚本 (<script>)

  • 共享全局作用域

  • 按顺序执行

  • 没有 import/export 机制

  • 变量提升至全局

  • 默认同步加载

ES 模块 (<script type="module">)

  • 每个模块有独立作用域

  • 自动采用严格模式

  • 支持 import/export

  • 只执行一次

  • 默认延迟加载

  • 受跨域限制

4. 常见使用模式

传统同步加载

<script src="app.js"></script>

延迟加载

<script defer src="app.js"></script>

异步加载

<script async src="app.js"></script>

模块加载

<script type="module" src="app.js"></script>

回退方案

<script type="module" src="modern.js"></script>
<script nomodule src="legacy.js"></script>

内联 JSON 数据

<script type="application/json" id="data">
  { "name": "张三", "age": 30 }
</script>

5. 实际案例分析

在我们的重构项目中,遇到了模块化相关的错误:

项目结构:

- config.js       // 配置文件
- utils.js        // 工具函数
- httpService.js  // HTTP请求封装
- buriedPoint.js  // 埋点逻辑
- appJump.js      // 跳转逻辑
- buriedLogic.js  // 主文件

错误: 当我们将代码重构为模块化结构时,浏览器报错:

Uncaught SyntaxError: Cannot use import statement outside a module (at buriedLogic.js:1:1)

解决方法: 在 HTML 中将 script 标签改为:

<script type="module" src="buriedLogic.js"></script>

结果: 问题成功解决,模块化代码正常运行。

6. 最佳实践

  1. 使用defer替代阻塞脚本

  2. 使用type="module"进行模块化开发

  3. 添加integrity属性增强安全性

  4. 避免过多内联脚本

  5. 使用构建工具管理复杂依赖

  6. 明确模块间依赖关系

  7. 按职责拆分模块

7. 现代前端构建工具

对于复杂项目,建议使用构建工具来处理模块依赖:

  • Webpack:功能全面的打包工具

  • Rollup:适合库开发的打包工具

  • Vite:基于 ES 模块的开发服务器和构建工具

  • Parcel:零配置的 Web 应用打包工具

这些工具可以自动处理模块间依赖,生成兼容性更好的代码,减少手动处理模块相关问题的需要。

最后更新时间:
贡献者: 何风顺
上一页
localStorage 与 sessionStorage 区别
下一页
JavaScript 中的`this`指向问题详解