vue-loader

news2024/10/5 23:29:29
  • Vue Loader 是一个 webpack 的 loader,它允许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件

起步

安装

npm install vue --save
npm install  webpack webpack-cli style-loader css-loader html-webpack-plugin vue-loader  vue-template-compiler  webpack-dev-server --save-dev

webpack.config.js

webpack.config.js

const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
    mode: 'development',
    devtool: false,
    entry: './src/main.js',
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new webpack.DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: true
        })
    ]
}

main.js

src\main.js

import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

App.vue

src\App.vue

<script>
console.log('App');
</script>

index.html

src\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue-loader</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

loader实现

文件结构

  • vue-loader内部主要有三个部分
    • vue-loader\index.js 实现了一个普通Loader,负责把SFC的不同区块转化为import语句
    • vue-loader\pitcher.js实现pitch Loader,用于拼出完整的行内路径
    • vue-loader\plugin.js 负责动态修改webpack配置,注入新的loader到rules规则中

基础知识

LoaderContext

  • Loader Context 表示在 loader 内使用 this 可以访问的一些方法或属性
  • this.callback可以同步或者异步调用的并返回多个结果的函数

pitching-loader

  • pitching-loaderloader 总是 从右到左被调用。在实际(从右到左)执行 loader 之前,会先 从左到右 调用 loader 上的 pitch 方法
  • loader 可以通过 request 添加或者禁用内联前缀,这将影响到 pitch 和执行的顺序,请看Rule.enforce

Rule.enforce

  • Rule.enforce可以用于指定loader种类

resource

  • Rule.resource会匹配 resource
  • Rule.resourceQuery会匹配资源查询

contextify

  • contextify返回一个新的请求字符串,尽可能避免使用绝对路径,将请求转换为可在内部使用requireimport在避免绝对路径时使用的字符串

@vue/compiler-sfc

  • compiler-sfc用于编译Vue单文件组件的低级实用程序
// main script
import script from '/project/foo.vue?vue&type=script'
// template compiled to render function
import { render } from '/project/foo.vue?vue&type=template&id=xxxxxx'
// css
import '/project/foo.vue?vue&type=style&index=0&id=xxxxxx'
// attach render function to script
script.render = render
// attach additional metadata
script.__file = 'example.vue'
script.__scopeId = 'hash'
export default script

工作流程

img

原始内容

import App from './App.vue'

第1次转换

  • 1.进入vue-loader的normal处理转换代码为

    import script from "./App.vue?vue&type=script&id=4d69bc76&lang=js"
    import {render} from "./App.vue?vue&type=template&id=4d69bc76&scoped=true&lang=js"
    import "./App.vue?vue&type=style&index=0&id=4d69bc76&scoped=true&lang=css"
    script.__scopeId = "data-v-4d69bc76"
    script.render=render
    export default script
    

第2次转换

  • 2.进入pitcher,不同区块返回不同内容
//script区块
export { default } from "-!../vue-loader/index.js!./App.vue?vue&type=script&id=4d69bc76&lang=js"; export * from "-!../vue-loader/index.js!./App.vue?vue&type=script&id=4d69bc76&lang=js"
//template区块
export * from "-!../vue-loader/templateLoader.js!../vue-loader/index.js!./App.vue?vue&type=template&id=4d69bc76&scoped=true&lang=js"
//style区块
export * from "-!../node_modules/style-loader/dist/cjs.js!../node_modules/css-loader/dist/cjs.js!../vue-loader/stylePostLoader.js!../vue-loader/index.js!./App.vue?vue&type=style&index=0&id=4d69bc76&scoped=true&lang=css"

第3次转换

  • 第二次执行vue-loader,从SFC中提取对应的区块内容,交给后面的loader
  • script内容直接编译返回
  • template内容交给templateLoader
  • style内容交给stylePostLoader

vue-loader\index.js

if (incomingQuery.get('type')) {
  return select.selectBlock(descriptor, id, loaderContext, incomingQuery);
}

编译script

  • 第一次的时候只走vue-loader,返回临时文件import script from "./App.vue?vue&type=script&id=4d69bc76&lang=js"
  • 第一次加载临时文件的时候会走pitcher,pitcher会拼出行内loader和加载模块的完整路径

webpack.config.js

webpack.config.js

+const { VueLoaderPlugin } = require('./vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
+const path = require('path')
module.exports = {
    mode: 'development',
    devtool: false,
    entry: './src/main.js',
    module: {
        rules: [
            {
                test: /\.vue$/,
+               loader: path.resolve(__dirname, 'vue-loader')
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new webpack.DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: true
        })
    ]
}

vue-loader\index.js

vue-loader\index.js

const compiler = require("vue/compiler-sfc");
const hash = require("hash-sum");
const VueLoaderPlugin = require("./plugin");
const select = require("./select");
function loader(source) {
    const loaderContext = this;
    const { resourcePath, resourceQuery = '' } = loaderContext;
    const rawQuery = resourceQuery.slice(1);
    const incomingQuery = new URLSearchParams(rawQuery);
    const { descriptor } = compiler.parse(source);
    const id = hash(resourcePath);
    if (incomingQuery.get('type')) {
        return select.selectBlock(descriptor, id, loaderContext, incomingQuery);
    }
    const code = [];
    const { script } = descriptor;
    if (script) {
        const query = `?vue&type=script&id=${id}&lang=js`;
        const scriptRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        code.push(`import script from ${scriptRequest}`);
    }
    code.push(`export default script`);
    return code.join('\n');
}
loader.VueLoaderPlugin = VueLoaderPlugin;
module.exports = loader;

plugin.js

vue-loader\plugin.js

class VueLoaderPlugin {
    apply(compiler) {
        const rules = compiler.options.module.rules;
        const pitcher = {
            loader: require.resolve('./pitcher'),
            //类似于test,用于判断资源的路径是否适用于此规则
            resourceQuery: query => {
                if (!query) {
                    return false;
                }
                let parsed = new URLSearchParams(query.slice(1));
                return parsed.get('vue') !== null;
            }
        };
        //把pitcher添加到rules数组的第一位
        compiler.options.module.rules = [pitcher, ...rules];
    }
}
module.exports = VueLoaderPlugin;

pitcher.js

vue-loader\pitcher.js

const pitcher = code => code;
const isNotPitcher = loader => loader.path !== __filename;
const pitch = function () {
    const context = this;
    const loaders = context.loaders.filter(isNotPitcher);
    const query = new URLSearchParams(context.resourceQuery.slice(1));
    return genProxyModule(loaders, context, query.get('type') !== 'template');
}
function genProxyModule(loaders, context, exportDefault = true) {
    const request = genRequest(loaders, context);
    return (exportDefault ? `export { default } from ${request}; ` : ``) + `export * from ${request}`;
}
function genRequest(loaders, context) {
    const loaderStrings = loaders.map(loader => loader.request);
    const resource = context.resourcePath + context.resourceQuery;
    return JSON.stringify(context.utils.contextify(context.context, '-!' + [...loaderStrings, resource].join('!')));
}
pitcher.pitch = pitch;
module.exports = pitcher;

select.js

vue-loader\select.js

const compiler_sfc = require("vue/compiler-sfc");
function selectBlock(descriptor, scopeId, loaderContext, query) {
    if (query.get('type') === `script`) {
        const script = compiler_sfc.compileScript(descriptor, { id: scopeId });
        loaderContext.callback(null, script.content);
        return;
    }
}
exports.selectBlock = selectBlock;

编译template

src\App.vue

src\App.vue

<template>
    <h1>hello</h1>
</template>
<script>
console.log('App');
</script>

vue-loader\index.js

vue-loader\index.js

const compiler = require("vue/compiler-sfc");
const hash = require("hash-sum");
const VueLoaderPlugin = require("./plugin");
const select = require("./select");
function loader(source) {
    const loaderContext = this;
    const { resourcePath, resourceQuery = '' } = loaderContext;
    const rawQuery = resourceQuery.slice(1);
    const incomingQuery = new URLSearchParams(rawQuery);
    const { descriptor } = compiler.parse(source);
    const id = hash(resourcePath);
    if (incomingQuery.get('type')) {
        return select.selectBlock(descriptor, id, loaderContext, incomingQuery);
    }
    const code = [];
    const { script } = descriptor;
    if (script) {
        const query = `?vue&type=script&id=${id}&lang=js`;
        const scriptRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        console.log(scriptRequest);
        code.push(`import script from ${scriptRequest}`);
    }
+   if (descriptor.template) {
+       const query = `?vue&type=template&id=${id}&lang=js`;
+       const templateRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
+       code.push(`import {render} from ${templateRequest}`);
+   }
+   code.push(`script.render=render`);
    code.push(`export default script`);
    return code.join('\n');
}
loader.VueLoaderPlugin = VueLoaderPlugin;
module.exports = loader;

plugin.js

vue-loader\plugin.js

class VueLoaderPlugin {
    apply(compiler) {
        const rules = compiler.options.module.rules;
        const pitcher = {
            loader: require.resolve('./pitcher'),
            resourceQuery: query => {
                if (!query) {
                    return false;
                }
                let parsed = new URLSearchParams(query.slice(1));
                return parsed.get('vue') !== null;
            }
        };
+       const templateCompilerRule = {
+           loader: require.resolve('./templateLoader'),
+           resourceQuery: query => {
+               if (!query) {
+                   return false;
+               }
+               const parsed = new URLSearchParams(query.slice(1));
+               return parsed.get('vue') != null && parsed.get('type') === 'template';
+           }
+       };
+       compiler.options.module.rules = [pitcher, templateCompilerRule, ...rules];
    }
}
module.exports = VueLoaderPlugin;

select.js

vue-loader\select.js

const compiler_sfc = require("vue/compiler-sfc");
function selectBlock(descriptor, scopeId, loaderContext, query) {
    if (query.get('type') === `script`) {
        const script = compiler_sfc.compileScript(descriptor, { id: scopeId });
        loaderContext.callback(null, script.content);
        return;
    }
+   if (query.get('type') === `template`) {
+       const template = descriptor.template;
+       loaderContext.callback(null, template.content);
+       return;
+   }
}
exports.selectBlock = selectBlock;

templateLoader.js

vue-loader\templateLoader.js

const compiler_sfc = require("vue/compiler-sfc");
const TemplateLoader = function (source) {
    const loaderContext = this;
    const query = new URLSearchParams(loaderContext.resourceQuery.slice(1));
    const scopeId = query.get('id');
    const { code } = compiler_sfc.compileTemplate({
        source,
        id: scopeId
    });
    loaderContext.callback(null, code);
}
module.exports = TemplateLoader;

编译style

webpack.config.js

webpack.config.js

const { VueLoaderPlugin } = require('./vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
module.exports = {
    mode: 'development',
    devtool: false,
    entry: './src/main.js',
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: path.resolve(__dirname, 'vue-loader')
            },
+           {
+               test: /\.css$/,
+               use: [
+                   'style-loader',
+                   'css-loader'
+               ]
+           }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new webpack.DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: true
        })
    ]
}

App.vue

src\App.vue

<template>
+   <h1 class="title">hello</h1>
</template>
<script>
console.log('App');
</script>
+<style>
+.title {
+    color: red;
+}
+</style>

vue-loader\index.js

vue-loader\index.js

const compiler = require("vue/compiler-sfc");
const hash = require("hash-sum");
const VueLoaderPlugin = require("./plugin");
const select = require("./select");
function loader(source) {
    const loaderContext = this;
    const { resourcePath, resourceQuery = '' } = loaderContext;
    const rawQuery = resourceQuery.slice(1);
    const incomingQuery = new URLSearchParams(rawQuery);
    const { descriptor } = compiler.parse(source);
    const id = hash(resourcePath);
    if (incomingQuery.get('type')) {
        return select.selectBlock(descriptor, id, loaderContext, incomingQuery);
    }
    const code = [];
    const { script } = descriptor;
    if (script) {
        const query = `?vue&type=script&id=${id}&lang=js`;
        const scriptRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        console.log(scriptRequest);
        code.push(`import script from ${scriptRequest}`);
    }
    if (descriptor.template) {
        const query = `?vue&type=template&id=${id}&lang=js`;
        const templateRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        code.push(`import {render} from ${templateRequest}`);
    }
+   if (descriptor.styles.length) {
+       descriptor.styles.forEach((style, i) => {
+           const query = `?vue&type=style&index=${i}&id=${id}&lang=css`;
+           const styleRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
+           code.push(`import ${styleRequest}`);
+       })
+   }
    code.push(`script.render=render`);
    code.push(`export default script`);
    return code.join('\n');
}
loader.VueLoaderPlugin = VueLoaderPlugin;
module.exports = loader;

plugin.js

vue-loader\plugin.js

+const langBlockRuleResource = (query, resource) => `${resource}.${query.get('lang')}`;
class VueLoaderPlugin {
    apply(compiler) {
        const rules = compiler.options.module.rules;
        const pitcher = {
            loader: require.resolve('./pitcher'),
            resourceQuery: query => {
                if (!query) {
                    return false;
                }
                let parsed = new URLSearchParams(query.slice(1));
                return parsed.get('vue') !== null;
            }
        };
+       const vueRule = rules.find(rule => 'foo.vue'.match(rule.test));
+       const clonedRules = rules.filter(rule => rule !== vueRule)
+           .map(rule => cloneRule(rule, langBlockRuleResource));
        const templateCompilerRule = {
            loader: require.resolve('./templateLoader'),
            resourceQuery: query => {
                if (!query) {
                    return false;
                }
                const parsed = new URLSearchParams(query.slice(1));
                return parsed.get('vue') != null && parsed.get('type') === 'template';
            }
        };
+       compiler.options.module.rules = [pitcher, templateCompilerRule, ...clonedRules, ...rules];
    }
}
+function cloneRule(rule, ruleResource) {
+    let currentResource;
+    const res = Object.assign(Object.assign({}, rule), {
+        resource: resources => {
+            currentResource = resources;
+            return true;
+        },
+        resourceQuery: query => {
+            if (!query) {
+                return false;
+            }
+            const parsed = new URLSearchParams(query.slice(1));
+            if (parsed.get('vue') === null) {
+                return false;
+            }
+            //取出路径中的lang参数,生成一个虚拟路径,传入规则中判断是否满足  
+            //通过这种方式,vue-loader可以为不同的区块匹配rule规则 
+            const fakeResourcePath = ruleResource(parsed, currentResource);
+            if (!fakeResourcePath.match(rule.test)) {
+                return false;
+            }
+            return true;
+        }
+    });
+    delete res.test;
+    return res;
+}
module.exports = VueLoaderPlugin;

select.js

vue-loader\select.js

const compiler_sfc = require("vue/compiler-sfc");
function selectBlock(descriptor, scopeId, loaderContext, query) {
    if (query.get('type') === `script`) {
        const script = compiler_sfc.compileScript(descriptor, { id: scopeId });
        loaderContext.callback(null, script.content);
        return;
    }
    if (query.get('type') === `template`) {
        const template = descriptor.template;
        loaderContext.callback(null, template.content);
        return;
    }
+   if (query.get('type') === `style` && query.get('index') != null) {
+       const style = descriptor.styles[Number(query.get('index'))];
+       loaderContext.callback(null, style.content);
+       return;
+   }
}
exports.selectBlock = selectBlock;

Scoped CSS

  • style标签有scoped属性时,它的 CSS 只作用于当前组件中的元素

App.vue

src\App.vue

<template>
    <h1 class="title">hello</h1>
</template>
<script>
console.log('App');
</script>
+<style scoped>
+.title {
+    color: red;
+}
+</style>

vue-loader\index.js

vue-loader\index.js

const compiler = require("vue/compiler-sfc");
const hash = require("hash-sum");
const VueLoaderPlugin = require("./plugin");
const select = require("./select");
function loader(source) {
    const loaderContext = this;
    const { resourcePath, resourceQuery = '' } = loaderContext;
    const rawQuery = resourceQuery.slice(1);
    const incomingQuery = new URLSearchParams(rawQuery);
    const { descriptor } = compiler.parse(source);
    const id = hash(resourcePath);
    if (incomingQuery.get('type')) {
        return select.selectBlock(descriptor, id, loaderContext, incomingQuery);
    }
+    const hasScoped = descriptor.styles.some(s => s.scoped);
    const code = [];
    const { script } = descriptor;
    if (script) {
        const query = `?vue&type=script&id=${id}&lang=js`;
        const scriptRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        code.push(`import script from ${scriptRequest}`);
    }
    if (descriptor.template) {
+       const scopedQuery = hasScoped ? `&scoped=true` : ``;
+       const query = `?vue&type=template&id=${id}${scopedQuery}&lang=js`;
        const templateRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
        code.push(`import {render} from ${templateRequest}`);
    }
    if (descriptor.styles.length) {
        descriptor.styles.forEach((style, i) => {
+           const scopedQuery = style.scoped ? `&scoped=true` : ``;
+           const query = `?vue&type=style&index=${i}&id=${id}${scopedQuery}&lang=css`;
            const styleRequest = JSON.stringify(loaderContext.utils.contextify(loaderContext.context, resourcePath + query));
            code.push(`import ${styleRequest}`);
        })
    }
+   if (hasScoped) {
+       code.push(`script.__scopeId = "data-v-${id}"`);
+   }
    code.push(`script.render=render`);
    code.push(`export default script`);
    return code.join('\n');
}
loader.VueLoaderPlugin = VueLoaderPlugin;
module.exports = loader;

pitcher.js

vue-loader\pitcher.js

+const isCSSLoader = loader => /css-loader/.test(loader.path);
+const stylePostLoaderPath = require.resolve('./stylePostLoader');
const pitcher = code => code;
const isNotPitcher = loader => loader.path !== __filename;
const pitch = function () {
    const context = this;
    const loaders = context.loaders.filter(isNotPitcher);
    const query = new URLSearchParams(context.resourceQuery.slice(1));
+   if (query.get('type') === `style`) {
+       const cssLoaderIndex = loaders.findIndex(isCSSLoader);
+       if (cssLoaderIndex > -1) {
+           const afterLoaders = loaders.slice(0, cssLoaderIndex + 1);
+           const beforeLoaders = loaders.slice(cssLoaderIndex + 1);
+           return genProxyModule([...afterLoaders, stylePostLoaderPath, ...beforeLoaders], context);
+       }
+   }
    return genProxyModule(loaders, context, query.get('type') !== 'template');
}
function genProxyModule(loaders, context, exportDefault = true) {
    const request = genRequest(loaders, context);
    return (exportDefault ? `export { default } from ${request}; ` : ``) + `export * from ${request}`;
}
function genRequest(loaders, context) {
+   const loaderStrings = loaders.map(loader => loader.request || loader);
    const resource = context.resourcePath + context.resourceQuery;
    return JSON.stringify(context.utils.contextify(context.context, '-!' + [...loaderStrings, resource].join('!')));
}
pitcher.pitch = pitch;
module.exports = pitcher;

stylePostLoader.js

vue-loader\stylePostLoader.js

const compiler_sfc = require("vue/compiler-sfc");
const StylePostLoader = function (source) {
    const query = new URLSearchParams(this.resourceQuery.slice(1));
    const { code } = compiler_sfc.compileStyle({
        source,
        id: `data-v-${query.get('id')}`,
        scoped: !!query.get('scoped')
    });
    this.callback(null, code);
};
module.exports = StylePostLoader;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1818710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud学习笔记 - 1、Boot和Cloud版本选型

文章目录 前言需要&#xff08;学习/用到&#xff09;的技术SpringBoot版本的选择我们为什么要使用 Java 17&#xff0c;以及SpringBoot 3.2 呢&#xff1f; SpringCloud 版本的选择SpringCloud 命名规则Springcloud Alibaba 版本的选择如何确定Boot&#xff0c;Cloud&#xff…

我国的AI大模型前景如何?

目前&#xff0c;我国的AI大模型市场前景很好。这个产业的发展源于多领域的广泛需求&#xff0c;包括办公、制造、金融、医疗、政务等场景中的降本增效、生产自动化、降低风险、提高诊断准确率、提高政务服务效率等诉求。这些领域的创新和发展共同推动了我国AI大模型产业的蓬勃…

C++中的结构体——结构体案例1_2

案例描述 学校正在做毕设项目&#xff0c;每位老师指导5名学生&#xff0c;总共有3名老师&#xff0c;需求如下 设计学生和老师的结构体&#xff0c;其中在老师的结构体中&#xff0c;有老师的姓名和一个存放5名学生的数组作为成员 学生的成员有姓名、考试分数&#xff0c;创…

又一个小伙伴在深圳上车安家~

又有同学在深圳买房上车了&#xff0c;招呼在深圳的大学同学聚餐&#xff0c;现在这个时间点买房还是挺强的。 他主要是小孩马上到了上学的年纪&#xff0c;考虑到孩子上学&#xff0c;所以今年四月份开始在深圳看房&#xff0c;很快就在罗湖锁定了一套二手房&#xff0c;没怎…

计算机组成原理 期末复习笔记整理(上)(个人复习笔记/侵删/有不足之处欢迎斧正)

零、计算机的发展 冯.诺依曼计算机的特点: 1.计算机由五大部件组成 2.指令和数据以同等地位存于存储器&#xff0c;可按地址寻访 3.指令和数据用二进制表示 4.指令由操作码和地址码组成 5.存储程序&#xff08;首次提出存储结构&#xff09; 6.以运算器为中心&#xff08;现代…

定时器0电机控制PWM输出

/*立式不锈钢波纹管机控制板2021 2 26 pcb PAST******/ #include <REG52.H> #include <intrins.H> #define uint unsigned int #define uchar unsigned char #define …

农产品商城系统农资电商商城系统java项目jsp web项目

农产品商城系统农资电商商城系统java项目jsp web项目 会员用户可以实现&#xff1a;注册登录、商品信息浏览、加入购物车、加入收藏、下单支付、查看公告、查看以及留言、个人信息管理 后台管理的实现&#xff1a;类别管理模块、商品管理模块、会员管理模块、订单管理、退货管…

11.1 Go 标准库的组成

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

redis未授权getshell整合利用

一、redis环境搭建 Redis下载地址&#xff1a;http://download.redis.io/releases/redis-4.0.2.tar.gz 1.靶机安装redis-centos7 第一步&#xff1a;下载wget yum -y install wget 第二步&#xff1a;下载redis wget http://download.redis.io/redis-stable.tar.gz 第三步&a…

英格索兰IngsollRang控制器过热维修讲解

【英格索兰IngsollRang控制器维修请关注】 【英格索兰IngsollRang控制器维修】 【英格索兰控制器维修】 一、IngsollRang扭矩枪控制器故障诊断 1. 检查环境温度&#xff1a;首先&#xff0c;确认工作场所的温度是否过高。如果环境温度超过设备规定的工作温度&#xff0c;可能…

数据结构入门:探索数据结构第一步

0.引言 在我们的日常生活中&#xff0c;经常需要管理大量的数据&#xff0c;就譬如学校中有好几千个学生&#xff0c;中国有十三亿人口&#xff0c;对于那么多的数据进行查找、插入、排序等操作就会比较慢。人们为了解决这些问题&#xff0c;提高对数据的管理效率&#xff0c;…

支持微信支付宝账单,极空间Docker部署一个开箱即用的私人账本『cashbook』

支持微信支付宝账单&#xff0c;Docker部署一个开箱即用的私人账本『cashbook』 哈喽小伙伴好&#xff0c;我是Stark-C~ 不知道屏幕前的各位富哥富姐们有没有请一个专业的私人财务助理管理自己的巨额资产&#xff0c;我不是给大家炫耀&#xff0c;我在月薪300的时候就已经有了…

WPF学习(2)--类与类的继承2-在窗口的实现

一、代码分析 1.Animal.cs 1.1 代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace AnimalNamespace {public class Animal{public string Name { get; set; }public int Age { get; set…

四、STP(生成树协议)

目录 一、经典生成树&#xff08;STP&#xff09; 1.1、作用 1.2、重要参数 1.3、BPDU 1.4、STP计算过程 1.5、STP接口状态 二、快速生成树&#xff08;RTSP&#xff09; 2.1、端口角色的增补 2.2、端口状态简化 2.3、配置BPDU报文修改 2.4、配置BPDU的处理 2.5、快…

从零开始手把手Vue3+TypeScript+ElementPlus管理后台项目实战十一(整体布局04之Header及用户注销)

新增Hearder 新增 src/layout/components/PageHeader.vue <template><div class"header-cont"><div><h1><router-link to"/">RealWorld</router-link></h1></div><div><template v-if"is…

ESP32-C6 闪耀 Apple WWDC24|使用 Embedded Swift 构建 Matter 设备

WWDC 是苹果公司的年度全球开发者大会&#xff0c;旨在向全球开发者展示最新技术和工具。在今年的 WWDC 2024 上&#xff0c;苹果宣布将 Swift 语言扩展至嵌入式设备领域。大会技术讲座中&#xff0c;乐鑫 ESP32-C6 也现身官方 Demo “Go Small with Embedded Swift​​​​​​…

Python-json模块

一、相关概念 # 序列号 和反序列号 # 序列号&#xff1a;把内存中的数据类型转成一种特定格式&#xff0c;这种格式&#xff08;json/pickle&#xff09;可以用于存储&#xff0c;或者传输给其他平台 import json # 内存中是数据类型 ----> 序列化 ----> 特定格式&…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 6月13日,星期四

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年6月13日 星期四 农历五月初八 1、 财政部&#xff1a;将在19日第一次续发行2024年20年期超长期特别国债。 2、 成本低&#xff0c;商载高&#xff0c;我国自主研制HH-100商用无人运输机首飞成功。 3、 四川甘孜州石渠县1…

水利水电安全员B类精选试题(附答案)

第1题:职业病病人除依法享有工伤保险外&#xff0c;依照有关民事法律&#xff0c;尚有获得赔偿的权利&#xff0c;有权向()提出赔偿要求。 | A.当地人民政府 B.医疗机构 C.企业主管部门 D.用人单位 正确答案:D 第2题:事故预防对策中()是利用法律.规程.标准以及规章制度等必要…

ChatGPT面试指南来袭!10个提示词助你应对自如

面试时刻,你准备充分了吗?许多求职者即将面对的面试,仿佛一场无形的战斗。关键的面试问题,犹如一个个智勇双全的敌人。那么,如何才能在这场战斗中取胜?本文为你提供面试中的十大秘密武器——提示词。正确使用提示词,你可以破解面试官的难题,从容应对各种困境。别小看这十个小…