十五、Webpack打包图片-js-Vue、Label命令、resolve模块解析

一、webpack打包图片

(1)加载图片案例准备

为了演示我们项目中可以加载图片,我们需要在项目中使用图片,比较常见的使用图片的方式是两种:

  1. img元素,设置src属性;
  2. 其他元素(比如div),设置background-image的css属性;

这个时候我们打包会报错:

javascript 复制代码
ERROR in ./src/img/zznh.png 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
 @ ./src/component/cpns.js 5:0-39 21:12-21
 @ ./src/index.js 2:0-25

(2)认识asset module type

我们当前使用的webpack版本是webpack5:

  • 在webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader;
  • 在webpack5开始,我们可以直接使用资源模块类型(asset module type),来替代上面的这些loader;

资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

  1. asset/resource 发送一个单独的文件并导出 URL。
    • 之前通过使用 file-loader 实现;
  2. asset/inline 导出一个资源的 data URI。
    • 之前通过使用 url-loader 实现;
  3. asset/source 导出资源的源代码
    • 之前通过使用 raw-loader 实现;
  4. asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。
    • 之前通过使用 url-loader,并且配置资源体积限制实现;

(3)asset module type的使用

我们在webpack.config.js配置文件中新增了这2行代码。然后打包之后,图片是正常能够加载的。

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: [ "style-loader", "css-loader", "less-loader", "postcss-loader" ],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        type: "asset"
      }
    ],
  },
}

(4)asset module type 四种模块类型的区别

我们讲下上述说的资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader。我们只看124,3是提供源码使用场景很少,有兴趣的小伙伴可以自己去玩一下。

① type: "asset/resource"

我们使用两种方式使用图片,然后将type设置成下图所示 type: "asset/resource" :

设置完以后我们删掉之前打包后的文件夹build,重新npm run build构建一下。

不难看出,webpack将我下面的两种图片打包进行了一次重命名,是通过哈希算法生成了对应的一个哈希值,对这2个图片资源进行一个复制。 实际上就是把这2张图片的资源路径给设置到我们创建的image元素和div的元素background那个地方。

结论:所以当 type: "asset/resource"时,webpack将打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中。


② type: "asset/inline"

我将打包过后的文件夹目录build删掉,type设置成type: "asset/inline",重新再进行一次打包

然后我们打开打包存放的目录build,发现没有图片了。

然后我们打开html 按F12查看发现图片被进行了编码,这个编码被称之为base64编码。编码之后的结果被放在inline,也就是行内了,放在build目录下面的bundle.js文件里面了。

具体base64编码是啥,我们后面再讲。

③ 各自的优劣势 type: "asset/inline" 和 type: "asset/resource"

我们现在先思考一个问题,把图片编码后放在js打包文件中是好还是不好呢?对于我们性能来说是有优势还是劣势呢?

javascript 复制代码
{
  test: /\.(png|jpe?g|svg|gif)$/,
  // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
  // type: "asset/resource"
        
  // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
  type: "asset/inline"
}

结论:

type: "asset/resource"的缺点:因为多了两张图片,所以需要多发送两次http网络请求,

type: "asset/inline"的缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。

④ url-loader的limit效果

对于 resource和 inline 的优缺点我们可以中和一下:

对于小一点的图片,可以进行base64编码。

对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片。

那怎么才能做到这一点呢?

开发中我们往往是小的图片需要转换,但是大的图片直接使用图片即可

  • 这是因为小的图片转换base64之后可以和页面一起被请求,减少不必要的请求过程;
  • 而大的图片也进行转换,反而会影响页面的请求速度;

我们需要两个步骤来实现:

  • 步骤一:将type修改为asset;
  • 步骤二:添加一个parser属性,并且制定dataUrl的条件,添加maxSize属性;
    • Data URL是一种特殊的URL,可以将数据编码为URL字符串中的一部分。它可以用于嵌入图像、音频、视频和其他数据,而不必将它们作为独立的文件进行加载。Data URL以"data:"作为协议标识符,后面跟着数据的MIME类型和编码,然后是实际的数据本身。例如,一个用base64编码的PNG图像的data URL可能是这样的:

      data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAI.......

      其中"data:image/png"指定了MIME类型,"base64"指定了数据使用的编码,"iVBORw0KGgoAAAANSUhEUgAAAAI......."是实际的base64编码数据。

我们把配置文件改成这样子:

再重新打包的时候发现他只复制了一个图片并用哈希值命名,还有一个图片被base64编码放在打包的bundle.js文件中了。

是不是满足我的诉求了,大于一定规格的图片我编码,小于一定规格的图片我直接复制后用哈希值命名。

自定义文件的输出路径和文件名

通过哈希值重新命名的图片,光看名字我们已经不知道他对应的原图是具体哪一个了。

那我们如何可以自定义文件的输出路径和文件名呢?

  • 方式一:修改output,添加assetModuleFilename属性;
  • 方式二:在Rule中,添加一个generator属性,并且设置filename;

我们先来试一下方法一:

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
        // 缺点;多图片加载的两次网络请求,两张图片就是两次请求。
        // type: "asset/resource"

        // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
        // 缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。
        // type: "asset/inline"

        // 3. 合理的规范:
        // 3.1 对于小一点的图片,可以进行base64编码
        // 3.2 对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 1kb=1024byte, 60 * 1024 就是最大值是60字节。
            maxSize: 60 * 1024, 
          },
        },
      },
    ],
  },
}

然后删掉打包的文件目录,重新打包npm run build,发现图片名字是不是变成了abc.png啦。

但是我们这个方法并不常用,因为如果是字体文件的话你用这个名字命名是不是不好?


我们试一下方法二:

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    // assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
        // 缺点;多图片加载的两次网络请求,两张图片就是两次请求。
        // type: "asset/resource"

        // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
        // 缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。
        // type: "asset/inline"

        // 3. 合理的规范:
        // 3.1 对于小一点的图片,可以进行base64编码
        // 3.2 对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 1kb=1024byte, 60 * 1024 就是最大值是60字节。
            maxSize: 60 * 1024, 
          },
        },
        generator: {
          filename: "cba.png"
        }
      },
    ],
  },
}

我们重新打包试一下效果:是不是打包的文件名变为cba.png啦。


但是现在我又有一个疑惑,我如果有多张图片的话,每张图片都叫cba.png是不是就不合适了?后面的会把前面的图片直接覆盖掉。

所以我们现在得用一个占位符:

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    // assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
        // 缺点;多图片加载的两次网络请求,两张图片就是两次请求。
        // type: "asset/resource"

        // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
        // 缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。
        // type: "asset/inline"

        // 3. 合理的规范:
        // 3.1 对于小一点的图片,可以进行base64编码
        // 3.2 对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 1kb=1024byte, 60 * 1024 就是最大值是60字节。
            maxSize: 60 * 1024,
          },
        },
        generator: {
          // 常见的占位符
          // 1. name: 指向原来的图片名称
          filename: "[name].png",
        },
      },
    ],
  },
}

效果是不是显而易见啦。[name] 指向的是原来的图片名称。


我们再试一下 [ext] ,他是处理文件的扩展名。

原来图片是什么文件扩展名,那就是什么扩展名。


这样子其实还会带来其他问题, 如果我在不同目录里,存在相同的名字的图片文件咋办?这样子的话打包起来还是会起冲突是不是。

所以我们得保留原来的哈希值,这样子就能文件名不会重复从而被覆盖。


此时又有小伙伴们觉得这个打包出来的图片名字太长了,我能不能对哈希值截取部分,当然可以。

javascript 复制代码
filename: "[name]_[hash:8][ext]"

有小伙伴们又提出来一个问题,我图片很多的话,打包和js文件一起全部放在build目录下,这样子看是不是有点乱?我们可不可以整理一下?当然可以!

我们可以设置

javascript 复制代码
filename: "img/[name]_[hash:8][ext]"

效果展示:是不是在打包目录下又多了一个img目录,打包的图片文件放在了build/img目录下?

完整代码我就放下面啦:

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    // assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
        // 缺点;多图片加载的两次网络请求,两张图片就是两次请求。
        // type: "asset/resource"

        // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
        // 缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。
        // type: "asset/inline"

        // 3. 合理的规范:
        // 3.1 对于小一点的图片,可以进行base64编码
        // 3.2 对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 1kb=1024byte, 60 * 1024 就是最大值是60字节。
            maxSize: 60 * 1024,
          },
        },
        generator: {
          // 常见的占位符
          // 1. name: 指向原来的图片名称
          // 2. ext: 指向原来的文件的扩展名
          // 3. hash: 保留原来webpack生成的hash
          filename: "[name]_[hash:8][ext]",
        },
      },
    ],
  },
}

二、babel

(1)为什么需要babel?

事实上,在开发中我们很少直接去接触babel,但是babel对于前端开发来说,目前是不可缺少的一部分:

  • 开发中,我们想要使用ES6+的语法,想要使用TypeScript,开发React项目,它们都是离不开Babel的;
  • 所以,学习Babel对于我们理解代码从编写到线上的转变过程至关重要;

那么,Babel到底是什么呢?

  • Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;
  • 包括:语法转换、源代码转换等;

(2)babel命令行使用

babel本身可以作为一个独立的工具(和postcss一样),不和webpack等构建工具配置来单独使用。

如果我们希望在命令行尝试使用babel,需要安装如下库:

  • @babel/core:babel的核心代码,必须安装;
  • @babel/cli:可以让我们在命令行使用babel;
javascript 复制代码
npm install @babel/cli @babel/core -D

使用babel来处理我们的源代码:

  • src:是源文件的目录;
  • --out-dir:指定要输出的文件夹dist;
javascript 复制代码
npx babel src --out-dir dist

(3)插件的使用(了解,真实开发中不会这么做)

比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件:

javascript 复制代码
npm install @babel/plugin-transform-arrow-functions -D

npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

查看转换后的结果:我们会发现 const 并没有转成 var

  • 这是因为 plugin-transform-arrow-functions,并没有提供这样的功能;
  • 我们需要使用 plugin-transform-block-scoping 来完成这样的功能;
javascript 复制代码
npm install @babel/plugin-transform-block-scoping -D 

npx babel src --out-dir dist --plugins=@babel/plugin-transform-block-scoping
						,@babel/plugin-transform-arrow-functions

完整配置如下:

javascript 复制代码
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    // assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        // 告诉webpack你要匹配什么类型的文件
        test: /\.css$/,
        // 用什么loader去处理
        use: [
          // 注意:  style-loader在css-loader的前面,因为loader的执行顺序是从右向左(或者说从下往上,从后往前)。
          // { loader: "style-loader" },
          // { loader: "css-loader" },
        ],
        // 简写一: 如果loader只有一个, 可以把use省略
        // loader: "css-loader"
        // 简写二: 如果不需要其他option属性时,可以直接写loader字符串形式。
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          // 下方注释掉的加options属性时,还可以在postcss.config.js文件中添加。
          // {
          //   loader: "postcss-loader",
          //   options: {
          //     postcssOptions: {
          //       plugins: ["autoprefixer"],
          //     },
          //   },
          // },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1. 打包两张图片,并且这两张图片有自己的地址,将地址设置到img/img-bg里面的background中
        // 缺点;多图片加载的两次网络请求,两张图片就是两次请求。
        // type: "asset/resource"

        // 2. 将图片进行base64的编码,并且直接将编码后的源码放到打包的js文件中。
        // 缺点: 造成js文件非常大,下载js文件本身消耗时间非常长。
        // type: "asset/inline"

        // 3. 合理的规范:
        // 3.1 对于小一点的图片,可以进行base64编码
        // 3.2 对于大一点的图片,单独的进行打包,形成url地址,单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 1kb=1024byte, 60 * 1024 就是最大值是60字节。
            maxSize: 60 * 1024,
          },
        },
        generator: {
          // 常见的占位符
          // 1. name: 指向原来的图片名称
          // 2. ext: 指向原来的文件的扩展名
          // 3. hash: 保留原来webpack生成的hash
          filename: "img/[name]_[hash:8][ext]",
        },
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              plugins: ["@babel/plugin-transform-arrow-functions", "@babel/plugin-transform-block-scoping"],
            },
          },
        ],
      },
    ],
  },
}

(4)babel.config.js文件

我们有那么多的语法,如果每个都要挨个安装插件的话,是不是特别麻烦?

而且在webpack.config.js文件中,该配置项是不是特别多 特别不好管理?

能不能像postcsss.config.js文件一样,单独抽离出来?回答是,当然可以。

webpack.config.js配置文件中相关test下注释掉该块代码,

新增babel.config.js文件。

(5) babel的预设preset

但是如果要转换的内容过多,一个个设置是比较麻烦的,我们可以使用预设(preset):

  • 后面我们再具体来讲预设代表的含义;

安装@babel/preset-env预设:

  • npm install @babel/preset-env -D

执行如下命令:

javascript 复制代码
npx babel src --out-dir dist --presets=@babel/preset-env

如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset,webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel。

是不是很方便?

常见的预设有三个:

  • env
  • react
  • TypeScript

三、webpack对vue文件的处理

(1)案例引导

在开发中我们会编写Vue相关的代码,webpack可以对Vue代码进行解析:

  • 接下来我们编写自己的App.vue代码;

(2)App.vue的打包过程

① vue-loader

我们对代码打包会报错:我们需要合适的Loader来处理文件。

这个时候我们需要使用vue-loader:

javascript 复制代码
npm install vue-loader -D

在webpack的模板规则中进行配置:

② @vue/compiler-sfc(正常来说安装vue的时候已经默认自动安装这个了)

打包依然会报错,这是因为我们必须添加@vue/compiler-sfc来对template进行解析:

javascript 复制代码
npm install @vue/compiler-sfc -D

另外我们需要配置对应的Vue插件:

重新打包即可支持App.vue的写法。

四、resolve模块解析

什么叫起别名?

我们举个🌰栗子~我在utils目录下创建一个abc/cba/nba/why/层级目录下创建一个test.js文件,然后在这个文件中引入utils目录下的math.js,

但是我目前这样导入是不是给人看的特别不清晰?

那我可不可以写成 下面这样子:

javascript 复制代码
import { sum } from "utils/math.js"

目前看是不是不行,因为你这么写的话是不是默认会从node/modules里去查找utils下面的math.js?

但是我又希望我在别的地方真的想用到这个的话,我能直接使用utils,那怎么办?回答:起别名。

我们直接上代码:

相关推荐
wen's1 小时前
React Native 0.79.4 中 [RCTView setColor:] 崩溃问题完整解决方案
javascript·react native·react.js
vvilkim1 小时前
Electron 自动更新机制详解:实现无缝应用升级
前端·javascript·electron
vvilkim1 小时前
Electron 应用中的内容安全策略 (CSP) 全面指南
前端·javascript·electron
aha-凯心2 小时前
vben 之 axios 封装
前端·javascript·学习
漫谈网络2 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
失落的多巴胺3 小时前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear3 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息3 小时前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月3 小时前
1.vue权衡的艺术
前端·vue.js·开源
RunsenLIu3 小时前
基于Vue.js + Node.js + MySQL实现的图书销售管理系统
vue.js·mysql·node.js