search
HomeWeb Front-endVue.jsHow to solve vue3 keepalive online problems

How to solve vue3 keepalive online problems

May 19, 2023 am 08:04 AM
vue3keepalive

1. Keepalive function

  • keepalive is a global component in vue3

  • keepalive itself will not be rendered or appear. In the dom node, but it will be rendered as a vnode. The cache and keys in the keepalive can be tracked through the vnode. Of course, this is only possible in the development environment. After the build is packaged, it is not exposed to the vnode (this needs to be confirmed again)

  • The most important function of keepalive is to cache components

  • keepalive updates the component cache through the LRU cache elimination strategy, which can make more effective use of memory and prevent Memory overflow, the maximum number of caches in the source code is 10, that is, after 10 components, the first cached components will begin to be eliminated

2. Keepalive usage scenarios

  • Let’s assume a scenario here: Page A is the home page =====> B page list page (pages that need to be cached) ======> C Details page is composed of When the C details page reaches the B page, it needs to return to the B cache page, including the basic data of the page and the scroll bar position information of the list. If you return from the B page to the A page, you need to clear the B cache page

  • Another scenario mentioned above: enter the page and cache it directly, and then it is over. This is relatively simple and will not be discussed in this article.

3. In the project Usage process

How to solve vue3 keepalive online problems

The keepalive component has a total of three parameters

  • include: strings, regular expressions, arrays, name matching can be passed Successful components will be cached

  • exclude: strings, regular expressions, arrays can be passed, components with successful name matching will not be cached

  • max: Transmittable number, limiting the maximum number of cached components, the default is 10

First add and introduce the keepalive component in the App.vue root code, you can find it here, I am here The cache is equivalent to the entire page. Of course, you can also control a certain area component in the page in a more fine-grained manner.

    <template>
        <router-view v-slot="{ Component }">
            <keep-alive :include="keepAliveCache">
                <component :is="Component" :key="$route.name" />
            </keep-alive>
        </router-view>
    </template>
    <script lang="ts" setup>
    import { computed } from "vue";
    import { useKeepAliverStore } from "@/store";
    const useStore = useKeepAliverStore();
    const keepAliveCache = computed(() => {
        return useStore.caches;
    });
    </script>

can be found through App.vue and saved through pinia (that is, vuex used in vue2) The page component to be cached is used to process the include cache and save the scroll bar information data in the page component.

    import { defineStore } from "pinia";
    export const useKeepAliverStore = defineStore("useKeepAliverStore", {
        state: () => ({
            caches: [] as any,
            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度
        }),
        actions: {
            add(name: string) {
                this.caches.push(name);
            },
            remove(name: string) {
                console.log(this.caches, &#39;this.caches&#39;)
                this.caches = this.caches.filter((item: any) => item !== name);
                console.log(this.caches, &#39;this.caches&#39;)
            },
            clear() {
                this.caches = []
            }
        }
    });

When the component route has just been switched, the component is written to the include through beforeRouteEnter. At this time, the component life cycle has not yet started. . If the execution of the component life cycle has already begun, it makes sense to write again.

So this hook function cannot be written in the setup and must be written separately. Of course, you can also switch to other hook functions of routing to handle beforeEach, but if you use it here, it seems that pinia cannot be used. This needs further research.

    import { useRoute, useRouter, onBeforeRouteLeave } from "vue-router";
    import { useKeepAliverStore } from "@/store";
    const useStore = useKeepAliverStore()
    export default {
        name:"record-month",
        beforeRouteEnter(to, from, next) {
            next(vm => {
                if(from.name === &#39;Home&#39; && to.name === &#39;record-month&#39;) {
                useStore.add(to.name)
                }
            });
        }
    }
    </script>

When the component route leaves, it is judged whether to move out of the cache. This hook can be written directly in the setup.

    onBeforeRouteLeave((to, from) => {
        console.log(to.name, "onBeforeRouteLeave");
        if (to.name === "new-detection-detail") {
            console.log(to, from, "进入详情页面不做处理");
        } else {
            useStore.remove(from.name)
            console.log(to, from, "删除组件缓存");
        }
    });

Process the scroll position cache in the two hook functions of keepalive. Get the position in the cache in onActivated, and record the position in the cache in onDeactivated.

    onActivated(() => {
        if(useStore.scrollList.get(routeName)) {
            const top = useStore.scrollList.get(routeName)
            refList.value.setScrollTop(Number(top))
        }
    });
    onDeactivated(() => {
        const top = refList.value.getScrollTop()
        useStore.scrollList.set(routeName, top)
    });

Define a method here to set scrollTop. Native javascript api

    const setScrollTop = (value: any) => {
        const dom = document.querySelector(&#39;.van-pull-refresh&#39;)
        dom!.scrollTop = value
    }

How to get the height at the same time? You must first register the scroll event, and then get the current scroll bar position through getScrollTop and save it

    onMounted(() => {
        scrollDom.value = document.querySelector(&#39;.van-pull-refresh&#39;) as HTMLElement
        const throttledFun = useThrottleFn(() => {
            console.log(scrollDom.value?.scrollTop, &#39;addEventListener&#39;)
            state.scrollTop = scrollDom.value!.scrollTop
        }, 500)
        if(scrollDom.value) {
            scrollDom.value.addEventListener(&#39;scroll&#39;,throttledFun)
        }
    })
    const getScrollTop = () => {
        console.log(&#39;scrollDom.vaue&#39;, scrollDom.value?.scrollTop)
        return state.scrollTop
    }

A useThrottleFn is used in the above registration scroll event , this class library is provided in @vueuse/core, which encapsulates many tools, which are very good. If you are interested, you can study it

    https://vueuse.org/shared/usethrottlefn/#usethrottlefn

At this time, you can also check the vnode of the found instance to find the keepalive, which is In the subcomponent next to keepalive

    const instance = getCurrentInstance()
    console.log(instance.vnode.parent) // 这里便是keepalive组件vnode
    // 如果是在开发环境中可以查看到cache对象
    instance.vnode.parent.__v_cache
    // vue源码中,在dev环境对cache进行暴露,生产环境是看不到的
    if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
        ;(instance as any).__v_cache = cache
    }

4, vue3 keepalive source code debugging

1, cloning code

    git clone git@github.com:vuejs/core.git

2, installation dependencies

    pnpm i

3 , If you cannot use pnpm, you can install it through npm first

    npm i pnpm -g

4. After the installation is completed, find the scripts

    // 在dev命令后添加 --source-map是从已转换的代码,映射到原始的源文件
    "dev": "node scripts/dev.js  --sourcemap"

in the package.json file in the root directory. Reference https://www.yisu .com/article/154583.htm

5. Executing pnpm run dev will build the vue source code

    pnpm run dev
    //则会出现以下,代表成功了(2022年5月27日),后期vue源代码作者可能会更新,相应的提示可能发生变更,请注意一下
    > @3.2.36 dev H:\github\sourceCode\core
    > node scripts/dev.js  --sourcemap
    watching: packages\vue\dist\vue.global.js
    //到..\..\core\packages\vue\dist便可以看到编译成功,以及可以查看到examples样例demo页面

6. Then in....\core\packages\vue\examples\composition Add an aehyok.html file, copy the following code, and then open it through the chrome browser, F12, find the Tab page of the source code, use the shortcut key Ctrl P and enter KeepAlive to find this component, and then right-click on the line mark on the left You can add breakpoints for debugging, or you can quickly jump to the code for debugging through the [Call Stack] on the right.

    <script src="../../dist/vue.global.js"></script>
    <script type="text/x-template" id="template-1">
        <div>template-1</div>
        <div>template-1</div>
    </script>
    <script type="text/x-template" id="template-2">
        <div>template-2</div>
        <div>template-2</div>
    </script>
    <script>
    const { reactive, computed } = Vue
    const Demo1 = {
        name: &#39;Demo1&#39;,
        template: &#39;#template-1&#39;,
        setup(props) {
        }
    }
    const Demo2 = {
        name: &#39;Demo2&#39;,
        template: &#39;#template-2&#39;,
        setup(props) {
        }
    }
    </script>
    <!-- App template (in DOM) -->
    <div id="demo">
        <div>Hello World</div>
        <div>Hello World</div>
        <div>Hello World</div>
        <button @click="changeClick(1)">组件一</button>
        <button @click="changeClick(2)">组件二</button>
        <keep-alive :include="includeCache">
            <component :is="componentCache" :key="componentName" v-if="componentName" />
        </keep-alive>
    </div>
    <!-- App script -->
    <script>
    Vue.createApp({
    components: {
        Demo1,
        Demo2
    },
    data: () => ({
        includeCache: [],
        componentCache: &#39;&#39;,
        componentName: &#39;&#39;,
    }),
    methods:{
        changeClick(type) {
            if(type === 1) {
                if(!this.includeCache.includes(&#39;Demo1&#39;)) {
                    this.includeCache.push(&#39;Demo1&#39;)
                }
                console.log(this.includeCache, &#39;000&#39;)
                this.componentCache = Demo1
                this.componentName = &#39;Demo1&#39;
            }
            if(type === 2) {
                if(!this.includeCache.includes(&#39;Demo2&#39;)) {
                    this.includeCache.push(&#39;Demo2&#39;)
                }
                console.log(this.includeCache, &#39;2222&#39;)
                this.componentName = &#39;Demo2&#39;
                this.componentCache = Demo2
            }
        }
    }
    }).mount(&#39;#demo&#39;)
    </script>

7. Debugging the source code found that the render function in the keepalive (or the return function in the setup) will be executed when the sub-component is switched, changing the logic cache

  • The first time you enter the page, the keepalive component will be executed once to initialize it.

  • Then click on component one and execute the render function again

  • Then click on the component Second, the render function will be executed again

8. Debugging screenshot description

How to solve vue3 keepalive online problems

##5. Brief analysis of vue3 keealive source code

By viewing vue3 KeepAlive.ts source code

    // 在setup初始化中,先获取keepalive实例
    // getCurrentInstance() 可以获取当前组件的实例
    const instance = getCurrentInstance()!
    // KeepAlive communicates with the instantiated renderer via the
    // ctx where the renderer passes in its internals,
    // and the KeepAlive instance exposes activate/deactivate implementations.
    // The whole point of this is to avoid importing KeepAlive directly in the
    // renderer to facilitate tree-shaking.
    const sharedContext = instance.ctx as KeepAliveContext
    // if the internal renderer is not registered, it indicates that this is server-side rendering,
    // for KeepAlive, we just need to render its children
    /// SSR 判断,暂时可以忽略掉即可。
    if (__SSR__ && !sharedContext.renderer) {
        return () => {
            const children = slots.default && slots.default()
            return children && children.length === 1 ? children[0] : children
        }
    }
    // 通过Map存储缓存vnode,
    // 通过Set存储缓存的key(在外面设置的key,或者vnode的type)
    const cache: Cache = new Map()
    const keys: Keys = new Set()
    let current: VNode | null = null
    if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
    ;(instance as any).__v_cache = cache
    }
    const parentSuspense = instance.suspense
    const {
    renderer: {
        p: patch,
        m: move,
        um: _unmount,
        o: { createElement }
    }
    } = sharedContext
    // 创建了隐藏容器
    const storageContainer = createElement(&#39;div&#39;)
    // 在实例上注册两个钩子函数 activate,  deactivate
    sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
        const instance = vnode.component!
        move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
        // in case props have changed
        patch(
            instance.vnode,
            vnode,
            container,
            anchor,
            instance,
            parentSuspense,
            isSVG,
            vnode.slotScopeIds,
            optimized
        )
        queuePostRenderEffect(() => {
            instance.isDeactivated = false
            if (instance.a) {
            invokeArrayFns(instance.a)
            }
            const vnodeHook = vnode.props && vnode.props.onVnodeMounted
            if (vnodeHook) {
            invokeVNodeHook(vnodeHook, instance.parent, vnode)
            }
        }, parentSuspense)
        if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
            // Update components tree
            devtoolsComponentAdded(instance)
        }
    }
    sharedContext.deactivate = (vnode: VNode) => {
        const instance = vnode.component!
        move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
        queuePostRenderEffect(() => {
            if (instance.da) {
            invokeArrayFns(instance.da)
            }
            const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted
            if (vnodeHook) {
            invokeVNodeHook(vnodeHook, instance.parent, vnode)
            }
            instance.isDeactivated = true
        }, parentSuspense)
        if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
            // Update components tree
            devtoolsComponentAdded(instance)
        }
    }
    // 组件卸载
    function unmount(vnode: VNode) {
        // reset the shapeFlag so it can be properly unmounted
        resetShapeFlag(vnode)
        _unmount(vnode, instance, parentSuspense, true)
    }
    // 定义 include和exclude变化时,对缓存进行动态处理
    function pruneCache(filter?: (name: string) => boolean) {
        cache.forEach((vnode, key) => {
            const name = getComponentName(vnode.type as ConcreteComponent)
            if (name && (!filter || !filter(name))) {
            pruneCacheEntry(key)
            }
        })
    }
    function pruneCacheEntry(key: CacheKey) {
        const cached = cache.get(key) as VNode
        if (!current || cached.type !== current.type) {
            unmount(cached)
        } else if (current) {
            // current active instance should no longer be kept-alive.
            // we can&#39;t unmount it now but it might be later, so reset its flag now.
            resetShapeFlag(current)
        }
        cache.delete(key)
        keys.delete(key)
    }
    // 可以发现通过include 可以配置被显示的组件,
    // 当然也可以设置exclude来配置不被显示的组件,
    // 组件切换时随时控制缓存
    watch(
    () => [props.include, props.exclude],
    ([include, exclude]) => {
        include && pruneCache(name => matches(include, name))
        exclude && pruneCache(name => !matches(exclude, name))
    },
    // prune post-render after `current` has been updated
    { flush: &#39;post&#39;, deep: true }
    )
    // 定义当前组件Key
    // cache sub tree after render
        let pendingCacheKey: CacheKey | null = null
        // 这是一个重要的方法,设置缓存
        const cacheSubtree = () => {
        // fix #1621, the pendingCacheKey could be 0
        if (pendingCacheKey != null) {
            cache.set(pendingCacheKey, getInnerChild(instance.subTree))
        }
        }
        onMounted(cacheSubtree)
        onUpdated(cacheSubtree)
        // 组件卸载的时候,对缓存列表进行循环判断处理
        onBeforeUnmount(() => {
            cache.forEach(cached => {
                const { subTree, suspense } = instance
                const vnode = getInnerChild(subTree)
                if (cached.type === vnode.type) {
                // current instance will be unmounted as part of keep-alive&#39;s unmount
                resetShapeFlag(vnode)
                // but invoke its deactivated hook here
                const da = vnode.component!.da
                da && queuePostRenderEffect(da, suspense)
                return
                }
                unmount(cached)
            })
        })
    // 同时在keepAlive组件setup生命周期中,return () => {} 渲染的时候,对组件进行判断逻辑处理,同样对include和exclude判断渲染。
    // 判断keepalive组件中的子组件,如果大于1个的话,直接警告处理了
    // 另外如果渲染的不是虚拟dom(vNode),则直接返回渲染即可。
    return () => {
        // eslint-disable-next-line no-debugger
        console.log(props.include, &#39;watch-include&#39;)
        pendingCacheKey = null
        if (!slots.default) {
            return null
        }
        const children = slots.default()
        const rawVNode = children[0]
        if (children.length > 1) {
            if (__DEV__) {
            warn(`KeepAlive should contain exactly one component child.`)
            }
            current = null
            return children
        } else if (
            !isVNode(rawVNode) ||
            (!(rawVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) &&
            !(rawVNode.shapeFlag & ShapeFlags.SUSPENSE))
        ) {
            current = null
            return rawVNode
        }
        // 接下来处理时Vnode虚拟dom的情况,先获取vnode
        let vnode = getInnerChild(rawVNode)
        // 节点类型
        const comp = vnode.type as ConcreteComponent
        // for async components, name check should be based in its loaded
        // inner component if available
        // 获取组件名称
        const name = getComponentName(
            isAsyncWrapper(vnode)
            ? (vnode.type as ComponentOptions).__asyncResolved || {}
            : comp
        )
        //这个算是最熟悉的通过props传递进行的参数,进行解构
        const { include, exclude, max } = props
        // include判断 组件名称如果没有设置, 或者组件名称不在include中,
        // exclude判断 组件名称有了,或者匹配了
        // 对以上两种情况都不进行缓存处理,直接返回当前vnode虚拟dom即可。
        if (
            (include && (!name || !matches(include, name))) ||
            (exclude && name && matches(exclude, name))
        ) {
            current = vnode
            return rawVNode
        }
        // 接下来开始处理有缓存或者要缓存的了
        // 先获取一下vnode的key设置,然后看看cache缓存中是否存在
        const key = vnode.key == null ? comp : vnode.key
        const cachedVNode = cache.get(key)
        // 这一段可以忽略了,好像时ssContent相关,暂时不管了,没看明白??
        // clone vnode if it&#39;s reused because we are going to mutate it
        if (vnode.el) {
            vnode = cloneVNode(vnode)
            if (rawVNode.shapeFlag & ShapeFlags.SUSPENSE) {
            rawVNode.ssContent = vnode
            }
        }
        // 上面判断了,如果没有设置key,则使用vNode的type作为key值
        pendingCacheKey = key
        //判断上面缓存中是否存在vNode
        // if 存在的话,就将缓存中的vnode复制给当前的vnode
        // 同时还判断了组件是否为过渡组件 transition,如果是的话 需要注册过渡组件的钩子
        // 同时先删除key,然后再重新添加key
        // else 不存在的话,就添加到缓存即可
        // 并且要判断一下max最大缓存的数量是否超过了,超过了,则通过淘汰LPR算法,删除最旧的一个缓存
        // 最后又判断了一下是否为Suspense。也是vue3新增的高阶组件。
        if (cachedVNode) {
            // copy over mounted state
            vnode.el = cachedVNode.el
            vnode.component = cachedVNode.component
            if (vnode.transition) {
            // recursively update transition hooks on subTree
            setTransitionHooks(vnode, vnode.transition!)
            }
            // avoid vnode being mounted as fresh
            vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE
            // make this key the freshest
            keys.delete(key)
            keys.add(key)
        } else {
            keys.add(key)
            // prune oldest entry
            if (max && keys.size > parseInt(max as string, 10)) {
            pruneCacheEntry(keys.values().next().value)
            }
        }
        // avoid vnode being unmounted
        vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
        current = vnode
        return isSuspense(rawVNode.type) ? rawVNode : vnode

The above is the detailed content of How to solve vue3 keepalive online problems. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:亿速云. If there is any infringement, please contact admin@php.cn delete
The Frontend Landscape: How Netflix Approached its ChoicesThe Frontend Landscape: How Netflix Approached its ChoicesApr 15, 2025 am 12:13 AM

Netflix's choice in front-end technology mainly focuses on three aspects: performance optimization, scalability and user experience. 1. Performance optimization: Netflix chose React as the main framework and developed tools such as SpeedCurve and Boomerang to monitor and optimize the user experience. 2. Scalability: They adopt a micro front-end architecture, splitting applications into independent modules, improving development efficiency and system scalability. 3. User experience: Netflix uses the Material-UI component library to continuously optimize the interface through A/B testing and user feedback to ensure consistency and aesthetics.

React vs. Vue: Which Framework Does Netflix Use?React vs. Vue: Which Framework Does Netflix Use?Apr 14, 2025 am 12:19 AM

Netflixusesacustomframeworkcalled"Gibbon"builtonReact,notReactorVuedirectly.1)TeamExperience:Choosebasedonfamiliarity.2)ProjectComplexity:Vueforsimplerprojects,Reactforcomplexones.3)CustomizationNeeds:Reactoffersmoreflexibility.4)Ecosystema

The Choice of Frameworks: What Drives Netflix's Decisions?The Choice of Frameworks: What Drives Netflix's Decisions?Apr 13, 2025 am 12:05 AM

Netflix mainly considers performance, scalability, development efficiency, ecosystem, technical debt and maintenance costs in framework selection. 1. Performance and scalability: Java and SpringBoot are selected to efficiently process massive data and high concurrent requests. 2. Development efficiency and ecosystem: Use React to improve front-end development efficiency and utilize its rich ecosystem. 3. Technical debt and maintenance costs: Choose Node.js to build microservices to reduce maintenance costs and technical debt.

React, Vue, and the Future of Netflix's FrontendReact, Vue, and the Future of Netflix's FrontendApr 12, 2025 am 12:12 AM

Netflix mainly uses React as the front-end framework, supplemented by Vue for specific functions. 1) React's componentization and virtual DOM improve the performance and development efficiency of Netflix applications. 2) Vue is used in Netflix's internal tools and small projects, and its flexibility and ease of use are key.

Vue.js in the Frontend: Real-World Applications and ExamplesVue.js in the Frontend: Real-World Applications and ExamplesApr 11, 2025 am 12:12 AM

Vue.js is a progressive JavaScript framework suitable for building complex user interfaces. 1) Its core concepts include responsive data, componentization and virtual DOM. 2) In practical applications, it can be demonstrated by building Todo applications and integrating VueRouter. 3) When debugging, it is recommended to use VueDevtools and console.log. 4) Performance optimization can be achieved through v-if/v-show, list rendering optimization, asynchronous loading of components, etc.

Vue.js and React: Understanding the Key DifferencesVue.js and React: Understanding the Key DifferencesApr 10, 2025 am 09:26 AM

Vue.js is suitable for small to medium-sized projects, while React is more suitable for large and complex applications. 1. Vue.js' responsive system automatically updates the DOM through dependency tracking, making it easy to manage data changes. 2.React adopts a one-way data flow, and data flows from the parent component to the child component, providing a clear data flow and an easy-to-debug structure.

Vue.js vs. React: Project-Specific ConsiderationsVue.js vs. React: Project-Specific ConsiderationsApr 09, 2025 am 12:01 AM

Vue.js is suitable for small and medium-sized projects and fast iterations, while React is suitable for large and complex applications. 1) Vue.js is easy to use and is suitable for situations where the team is insufficient or the project scale is small. 2) React has a richer ecosystem and is suitable for projects with high performance and complex functional needs.

How to jump a tag to vueHow to jump a tag to vueApr 08, 2025 am 09:24 AM

The methods to implement the jump of a tag in Vue include: using the a tag in the HTML template to specify the href attribute. Use the router-link component of Vue routing. Use this.$router.push() method in JavaScript. Parameters can be passed through the query parameter and routes are configured in the router options for dynamic jumps.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.