How to Use Vue.js Without NPM in Legacy Projects

How to Use Vue.js Without NPM in Legacy Projects

11/26/2025 Vue.js By Tech Writers
Vue.jsCDNLegacy WebsiteFrontend DevelopmentJavaScriptjQuery MigrationWeb Development

Did you know that Vue.js can be embedded directly into web pages without build processes and npm? Yes, Vue.js can be integrated just like jQuery that you’ve been using for ages!

Why Use Vue.js from CDN?

If you have legacy websites still using jQuery and want to add modern features without rewriting the entire source code, you can try this easy method to integrate Vue.js through CDN.

Benefits of Using Vue.js via CDN

  • No need for build tools (webpack, vite, etc.)
  • No need to install npm packages
  • Easy integration into old websites
  • Still get modern developer experience
  • No need to rewrite entire application code

Tutorial: Adding Vue.js to Legacy Websites

Here are the complete steps to integrate Vue.js into your web pages:

1. Add Vue.js CDN to HTML <head> Tag

First, add the Vue.js CDN link to the <head> section of your HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js CDN Example</title>
    
    <!-- Add Vue.js from CDN -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <!-- Your HTML content -->
</body>
</html>

Vue.js CDN Options:

  • Vue 3: https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js
  • Vue 2: https://cdn.jsdelivr.net/npm/vue@2
  • Unpkg: https://unpkg.com/vue@3/dist/vue.global.js

2. Define Root Element for Vue.js

Choose an element on the page (e.g., <div id="app">) that will become the Vue application root. This is the area where Vue.js will manage content and interactivity:

<body>
    <div id="app">
        <h1>{{ message }}</h1>
        <button @click="updateMessage">Click Me!</button>
    </div>
</body>

3. Write Vue.js Script

Add the Vue.js JavaScript code before the closing </body> tag:

For Vue 3:

<script>
    const { createApp } = Vue;
    
    createApp({
        data() {
            return {
                message: 'Hello from Vue.js 3!'
            }
        },
        methods: {
            updateMessage() {
                this.message = 'Message has been updated!';
            }
        }
    }).mount('#app');
</script>

For Vue 2:

<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello from Vue.js 2!'
        },
        methods: {
            updateMessage() {
                this.message = 'Message has been updated!';
            }
        }
    });
</script>

Complete Example: Simple To-Do List

Here’s a complete implementation of a To-Do List using Vue.js from CDN:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js To-Do List</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
        }
        .todo-item {
            padding: 10px;
            margin: 5px 0;
            background: #f4f4f4;
            border-radius: 5px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .completed {
            text-decoration: line-through;
            opacity: 0.6;
        }
        button {
            padding: 5px 10px;
            cursor: pointer;
        }
        input[type="text"] {
            padding: 8px;
            width: 80%;
            margin-right: 10px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>{{ title }}</h1>
        
        <div>
            <input 
                v-model="newTodo" 
                @keyup.enter="addTodo"
                type="text" 
                placeholder="Add new task...">
            <button @click="addTodo">Add</button>
        </div>
        
        <div v-if="todos.length === 0" style="margin-top: 20px;">
            <p>No tasks. Add your first task!</p>
        </div>
        
        <div v-else>
            <div 
                v-for="(todo, index) in todos" 
                :key="index"
                class="todo-item"
                :class="{ completed: todo.done }">
                <span @click="toggleTodo(index)">
                    {{ todo.text }}
                </span>
                <button @click="removeTodo(index)">Delete</button>
            </div>
        </div>
        
        <p style="margin-top: 20px;">
            Total: {{ todos.length }} tasks | 
            Completed: {{ completedCount }} | 
            Remaining: {{ remainingCount }}
        </p>
    </div>

    <script>
        const { createApp } = Vue;
        
        createApp({
            data() {
                return {
                    title: 'My Task List',
                    newTodo: '',
                    todos: []
                }
            },
            computed: {
                completedCount() {
                    return this.todos.filter(todo => todo.done).length;
                },
                remainingCount() {
                    return this.todos.filter(todo => !todo.done).length;
                }
            },
            methods: {
                addTodo() {
                    if (this.newTodo.trim()) {
                        this.todos.push({
                            text: this.newTodo,
                            done: false
                        });
                        this.newTodo = '';
                    }
                },
                removeTodo(index) {
                    this.todos.splice(index, 1);
                },
                toggleTodo(index) {
                    this.todos[index].done = !this.todos[index].done;
                }
            }
        }).mount('#app');
    </script>
</body>
</html>

Integration with Existing jQuery

You can use Vue.js and jQuery together on the same page:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue.js + jQuery</title>
    
    <!-- jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    
    <!-- Vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <!-- jQuery Section -->
    <div id="jquery-section">
        <h2>jQuery Section</h2>
        <button id="jquery-btn">Click with jQuery</button>
        <p id="jquery-output"></p>
    </div>
    
    <!-- Vue.js Section -->
    <div id="app">
        <h2>Vue.js Section</h2>
        <button @click="count++">Click with Vue: {{ count }}</button>
    </div>

    <script>
        // jQuery code
        $('#jquery-btn').click(function() {
            $('#jquery-output').text('jQuery works!');
        });
        
        // Vue.js code
        const { createApp } = Vue;
        createApp({
            data() {
                return {
                    count: 0
                }
            }
        }).mount('#app');
    </script>
</body>
</html>

When Should You Use Vue.js via CDN?

✅ Use CDN If:

  1. Legacy websites that are difficult to completely change
  2. Small projects or quick prototypes
  3. Don’t need build tools and modern toolchain
  4. Want to add interactive features without major migration
  5. Learning and experimenting with Vue.js

❌ Don’t Use CDN If:

  1. New projects built from scratch
  2. Large applications with many components
  3. Need maximum performance optimization
  4. Require Single File Components (.vue files)
  5. Need TypeScript and modern tooling

Vue.js CDN Best Practices

1. Use Production Version

For production, use the minified version:

<!-- Development (with warnings) -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>

<!-- Production (optimized) -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>

2. Specify Exact Version

Don’t use @latest, specify an exact version:

<!-- ❌ Not recommended -->
<script src="https://cdn.jsdelivr.net/npm/vue@latest"></script>

<!-- ✅ Recommended -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>

3. Use SRI (Subresource Integrity)

For security, add integrity hash:

<script 
    src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"
    integrity="sha384-..."
    crossorigin="anonymous">
</script>

4. Consider Caching

Use popular CDNs so browsers can leverage cache:

  • jsDelivr: https://cdn.jsdelivr.net/npm/vue@3
  • unpkg: https://unpkg.com/vue@3
  • cdnjs: https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.15/vue.global.prod.min.js

Migrating from jQuery to Vue.js

If you want to start gradually migrating from jQuery to Vue.js:

jQuery Code:

// jQuery
$('#button').click(function() {
    $('#output').text('Hello World');
    $('#output').addClass('active');
});

Vue.js Equivalent:

<div id="app">
    <button @click="updateText">Click</button>
    <p :class="{ active: isActive }">{{ message }}</p>
</div>

<script>
const { createApp } = Vue;
createApp({
    data() {
        return {
            message: '',
            isActive: false
        }
    },
    methods: {
        updateText() {
            this.message = 'Hello World';
            this.isActive = true;
        }
    }
}).mount('#app');
</script>

Limitations of Vue.js via CDN

Keep in mind some limitations when using Vue.js from CDN:

  1. No Single File Components (.vue files)
  2. No Hot Module Replacement (HMR)
  3. No automatic code splitting
  4. No built-in TypeScript support
  5. No tree-shaking for bundle optimization
  6. No preprocessors (Sass, Less, etc.)

Alternative: Petite-Vue for Simpler Cases

If you only need basic Vue.js features, consider using petite-vue (only 6KB):

<script src="https://unpkg.com/petite-vue" defer init></script>

<div v-scope="{ count: 0 }">
    <button @click="count++">{{ count }}</button>
</div>

Petite-vue is perfect for progressive enhancement and simple interactions.

Conclusion

Vue.js can be easily integrated into legacy websites using CDN, without build processes or npm. This approach is ideal for:

  • ✅ Adding interactive features to old pages
  • ✅ Improving developer experience without major migration
  • ✅ Quick learning and prototyping
  • ✅ Gradual transition from jQuery to modern frameworks

However, for new projects and large applications, it’s still recommended to use Vue.js with npm and build tools to get maximum benefits from the Vue.js ecosystem.

Resources


Was this article helpful? If you successfully integrated Vue.js into your legacy website, share your experience in the comments! Don’t forget to subscribe for more Vue.js tutorials! 🚀