Ardından, Vue.js temel özellikleri ve klasik kullanımı ile pek çok detaya ve örneğe değinmeye çalıştım. Bir önceki yazıda (ve sonraki anlatımlarda temel olarak ele alınacak olan) ise NPM ve CLI kullanımı ile diğer yapılandırma süreçlerine geçmiş olduk. Bu yazıda ise .vue uzantılı dosyaları nasıl kullanabileceğimizden bahsedeceğim.
Vue.js Single-File JavaScript Bileşenleri
Vue projelerinde global component’leri Vue.component
ile tanımlamakta ve taşıyıcı (container) ögesini (element) new Vue({ el: '#container' })
ile işaretlemekteyiz. Şimdiye değin Vue işlemlerini bir HTML ve JavaScript dosyaları (kimi zaman aynı dosyada) ile gerçekleştirdiğimizi hatırlarsınız. Bu örneklerde component’leri (bileşenler) de aynı dosya içerisinde bulundurmaktaydık. Bu süreç basit uygulamalar geliştirirken pek sorun yaratmasada, söz konusu kapsamlı çalışmalar olduğunda kod ve içerik yönetiminde karmaşa oluşmasına neden olmakta. Bu sorunlardan bazılarını şu şekilde özetleyebiliriz;
- Global definitions; her component için benzersiz bir isim kullanmamız gerekir,
- String templates; syntax highlighting (söz dizimi vurgulama) ve okunaksızlaşan HTML içeriği
- No CSS support; HTML ve JS içeriği modüler bir şekilde yönetilebilirken, CSS akışının component tanımı dışından yönetilmesi
- No build step; Pug veya Babel gibi önişlemciler (preprocessors) yerine HTML ve ES5 JavaScript ile sınırlandırması
Uygulamanın kapsamı genişledikçe yukarıda, maddeler halinde ifade edilen sorunlar oldukça can sıkıcı hale gelecektir. İşte, bu gibi durumlara çözüm olarak single-file component kullanımı sunulmakta. Bu kullanım için *.vue
uzantılı dosyalar kullanılmakta ve bu dosyalar Webpack veya Browserify gibi araçlarla yönetilebilmekte. Hemen basit bir örnekle şimdiye kadar bahsettiğimiz tüm konuları toparlayalım:
<template>
<p>{{ message }}</p>
</template>
<script>
module.exports = {
data: function () {
return {
message: 'Hello World!'
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
Oldukça basit bir şekilde oluşturduğumuz dosyamızı hello.vue
adıyla kayıt edelim. Görüldüğü üzere, aynı dosya içerisinde, birbiriyle ilişkili 3 bölüm yer alıyor:
<template>...</template>
<script>...</script>
<style>...</style>
// ya da
<template>...</template>
<script src="..."></script>
<style src="..."></style>
Bu sayede kodlar okunaklı bir şekilde görüntülenebiliyor, CommonJS modüllerini5 kullanabiliyoruz, component kapsamlı (component-scpoed) CSS’ler yazabilmekteyiz6, Pug, Babel (ES2015 modülleriyle) ve Stylus gibi araçlardan faydalanabilmekteyiz.
<template lang="jade">
div
p {{ meesage }}
diger-component
</template>
<script>
import digerComponent from './digerComponent.vue'
export default {
components: {
digerComponent
},
data () {
return {
message: 'Hello World!'
}
}
}
</script>
<style lang="stylus" scoped>
p
font-size 2em
text-align center
</style>
Yukarıdaki her iki örnekte de görüldüğü üzere component instance’ları export default içerisinde ve data function olarak tanımlamaktayız. Bu arada, yukarıdaki Jade sadece kullanılabilecek modern web geliştirme araçlarından sadece biri; Bublé, TypeScript, SCSS, PostCSS, Webpack kullanıyorsanız vue-loader ve daha pek çok seçenek kolaylıkla projelerinize entegre edilebilir.
Not: Vue-loader ya da vueify kullanımında, *.vue
içeriğindeki template’ler önceden derlenmiş (pre-compiled) olacaklar. Bu nedenle projeyi paketlerken (final bundle) bir compiler’a ihtiyacınız olmayacaktır. Bu nedenle sadece runtime-only opsiyonunu1 kullanabilirsiniz.
Single-file component konusuna bir eklemede bulunmak istiyorum. Yukarıdaki yapıda dosyalar oluşturmak için temel düzeyde NPM (Node Package Manager) ve Modern JavaScript (ES2015/16) bilgisine sahip olmanız gerekiyor. Peki, farklı bir yöntem söz konusu olamaz mı?
Tarayıcıda Vue.js Single-File JavaScript Bileşenleri Çalıştırmak
Vue Kurulum ve Kullanım Yöntemleri başlıklı yazının son bölümünde Vue’nun 2.6 sürümü itibariyle internet tarayıcıları için ES Module (ESM) build seçeneğini (vue.esm.browser.js) sunduğunu belirtmiştim3.
<script type="module">...</script>
Paylaşımlı bir hosting alanı kullanıyor olabilirsiniz ya da başka bir nedenden dolayı NPM kullanamıyor olabilirsiniz. Bu durumda *.vue
dosyalarını yapılandırmanız pek mümkün olmayacaktır. Peki, bu durumda nasıl ilerleyebiliriz?
İnternet tarayıcıların gün geçtikçe daha donanımlı hale geldiği aşikar ve yakın zamandır native JavaScript modülleri de desteklenmeye başlandı. Bu sayede Vue component’lerini dosyalarımız içerisinde herhangi bir yapılandırma adımı gerekmeksizin organize bir şekilde kullanabilmemiz de mümkün hale geldi.
Bu işlemi 2 şekilde gerçekleştirebiliriz. İlki, Vue CLI üzerinden simple yapılandırması.
vue init simple yeni-proje
Elbette bu işlem için VUE CLI yapılandırmış olmamız gerekecek. Yani, NPM’e yine ihtiyacımız olacak. Diğer yöntemde ise tamamen el yordamı ile ilerlemekteyiz. Hemen bir örnekle başlayalım ve bir index.html
dosyası oluşturalım.
<!DOCTYPE html>
<html><head>
<title>Vue Example</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
</head><body>
<section id="app" class="section" v-cloak>
<single-file-component></single-file-component>
</section>
<script type="module" src="./app.mjs"></script>
</body></html>
index.html
dosyamız içerisinde gördüğünüz üzere single-file-component
adında bir component’imiz yer alıyor. Asıl önemli bölüm ise sonda yer alan modul tanımımız.
<script type="module" src="./app.mjs"></script>
type
ifadesini farklı bir tanım (mime type) yaptığınızda Uncaught SyntaxError: Unexpected identifier
hatası alırsınız. Çünkü, ilgili type tanımı content-type‘i ifade etmekte7. Diğer yandan, index.html
dosyasını çift tıklatarak görüntülemek istediğinizde, özellikle Chrome kullanıyorsanız, CORS policy uyarısını almanız oldukça muhtemel.
Access to script at 'file:///.../app.mjs' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Dolayısıyla bu işlemler için basit bir web server’a ihtiyacınız olacak. macOS kullanıyorsanız macOS X Üzerinde Kurulumsuz PHP Çalıştırmak başlıklı yazıma göz atabilirsiniz.
Elbette hepsi bu kadar değil. mjs (*.mjs
) dosyalarını8 çalıştırabilmek için ayrıca sunucu yapılandırmasına (Module Identifier: mime_module, Source File: mod_mime.c)9 ihtiyaç duyulmakta. Normal şartlarda .htaccess dosyasına şu tanımları eklemeniz yeterli olacaktır10.
<IfModule mime_module>
AddHandler application/javascript .mjs
</IfModule>
<IfModule mod_mime.c>
AddType text/javascript js mjs
</IfModule>
<IfModule mod_mime.c>
AddCharset utf-8 .mjs
</IfModule>
Eğer hala Failed to load module script
hatası alıyorsanız mime type tanımlama işlemini doğrudan mime.types
dosyası üzerinden yapmamız gerekecektir.
Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
Bunun için şu adımları izleyebilirsiniz:
- apache2 içerisindeki
mime.types
dosyasını terminal üzerinden yönetici modunda açalım;
sudo nano /private/etc/apache2/mime.types
application/javascript
satırını ve bu satıra ilişikjs
alanına mjs yazalım ve dosyası kayıt edip kapatalım11.
application/javascript js mjs
- Sunucuyu yeniden başlatalım.
sudo apachectl restart
Evet, hepsi bu kadar. Aynı işlemi NGINX için de yapmak için conf > mime.types adımlarını izlemeliyiz12. types{}
içerisinde pek çok tanım yapıldığını görebilirsiniz. Ardından, applicationjavascript
için yapılan js
tanımını js mjs
şeklinde güncellemeniz yeterli. Aynı şekilde, dosyayı kaydetip kapatmalı ve sunucunu yeniden başlatmalısınız.
types {
//...
application/javascript js mjs;
//...
}
Bu adımların ardından module kullanımında bir sorun yaşamıyor olmamız gerekiyor. O halde, yukarıdaki örneğimize devam edelim ve app.mjs
dosyamızı oluşturalım.
import singleFileComponent from './comp.mjs';
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue 2.6.0+ ESM Browser Build!'
},
components: {
singleFileComponent
}
});
İlk satırda bir import
işlemi görmektesiniz. Module kullanımının bize sağladığı avantajlardan biri bu.
import singleFileComponent from './comp.mjs';
Bu sayede modüler bir şekilde component’lerimizi ayrı ayrı organize edebilmekteyiz. Şimdi de bu comp.mjs
isimli component’imizi oluşturalım.
export default {
template: `
<div>
<h1>Single-file JavaScript Component</h1>
<p>{{ message }}</p>
</div>
`,
data() {
return {
message: 'Oh hai from the component'
}
}
}
Hepsi bu kadar!
Görüldüğü üzere farklı dosyalar içerisinde component’lerimizi kendi data function’ları ve template içerikleriyle birlikte oluşturabilmekte ve istediğimiz gibi component’ler arasında import işlemleri gerçekleştirebilmekteyiz.
http-vue-loader ve Vue Single-file Component Kullanımı
Yazının pek çok yerinde builder kullanımıyla *.vue
uzantılı dosyalar arasında bir ilişki olduğundan bahsettim. Ancak, bir istisna söz konusu. İlgili dosyaları node.js ortamından bağımsız, build adımı olmaksızın çalıştırmanın bir yolu mevcut. Bu işlem için awesome-vue listesinde de yer alan http-vue-loader13 plugin’inden faydalanabiliriz. Yukarıdaki örneğimizi şimdide *.vue
uzantılı dosyalarla yineleyelim. İlk olarak index.html
dosyamızı oluşturalım.
<!DOCTYPE html>
<html>
<head>
<title>Vue Example</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/http-vue-loader"></script>
</head>
<body>
<section id="app" class="section" v-cloak>
<single-file-component></single-file-component>
</section>
<script type="text/javascript">
var app = new Vue({
el: '#app',
components: {
'single-file-component': httpVueLoader('comp.vue')
}
});
</script>
</body></html>
app.js
dosyamıza geçelim.
var app = new Vue({
el: '#app',
components: {
'single-file-component': httpVueLoader('comp.vue')
}
});
Component tanımında, gördüğünüz üzere comp.vue
dosyasını httpVueLoader()
ile çağırmamız gerekmekte. comp.vue
dosyamızı da oluşturalım.
<template>
<div>
<h1>Single-file JavaScript Component</h1>
<p>{{ message }}</p>
</div>
</template>
<script>module.exports = {
data() {
return {
message: "Oh hai from the component"
};
}
};
</script>
<style>
p {
font-size: 2em;
text-align: center;
}
</style>
Vue tarafından Example Sandbox14 15 başlığı altında paylaşılan Simple Todo App with Vue16 17 uygulamasını module ile karşılaştırma yapabilmek için18 yeniden ele alabiliriz.
Görüldüğü üzere, vue dosyaları bize daha düzenli bir geliştirme ortamı sunmakta. İhtiyaçlarınız doğrultusunda size en uygun adımı seçebilirsiniz. Ben, sonraki örneklerde Vue CLI aracılığıyla işlemler yapacağım için ilgili adımlarda yeri geldikçe webpack’e dair de notlar paylaşacağım. Diğer yandan, module kullanımına dair yeni yazılar yayınlayacağım. Şimdilik bu kadar. Aşağıda ek anlatıların ve örneklerin yer aldığı bazı bağlantılar iletiyorum.
- What’s next for JS modules?
- Using JavaScript modules on the web
- Files with .mjs extension for JavaScript modules
- Module specifiers: what’s new with ES modules?
- New in Vue: ES Module Browser Build
- Vue.js Single-File JavaScript Components In The Browser
- Explanation of Different Builds. Vue v2.x ↩ ↩
- Explanation of Different Builds. Vue v3.x ↩
- Terms. Vue v2.x ↩ ↩
- Terms. Vue v3.x ↩
- What is a webpack Module. Webpack ↩
- Scoped CSS. Vue Loader ↩
-
Correct
Content-Type
header. Webhint ↩ - Browser-specific differences between modules and classic scripts. JavaScript modules. v8 ↩
- Apache Module mod_mime ↩
- Basic server configuration for Apache. Webhint ↩
- Common MIME types. MDN web docs ↩
- nginx/conf/mime.types. GitHub ↩
- FranckFreiburger/http-vue-loader. GitHub ↩
- Example Sandbox. Vue v2.x ↩
- Example Sandbox. Vue v3.x ↩
- Simple Todo App with Vue ↩
- Vue Todo List App with Single File Component ↩
- vue-examples/2_intermediate. GitLab ↩