intro
场景1:
如果你发现有一个旧的meteor项目的版本是1.8.1的,是在2019年5月前创建的
你现在2021年10月,还想创建一个1.8.1的meteor项目,可以通过指定版本号来创建项目,如下:
meteor create vue-meteor-app --release 1.8.1
然后:
但是当你创建好项目,想通过在命令行输入meteor
来运行时,发现报错了。
Uncaught Error: jQuery not found
他说你缺少jquery这个包,而且你不能通过npm i jquery
来安装
而必须通过meteor add jquery
这个命令来添加jquery这个包
meteor add jquery
好的,现在项目能正常运行了。
场景2:
但是当你信心满满地按照官网的文档,在meteor中集成vue框架时,发现又报错了
While loading plugin vue-component
from package akryum:vue-component
: Cannot find module
你就会想,项目版本一样都是1.8.1,步骤流程也是按照官网来的,为什么2019年创建时就可以,而现在2021年创建就不行了呢?到底哪里改变了。
后来发现,原来是安装vue转换必备插件akryum:vue-component
的时候,版本发生改变了。
通过查看2019年的旧项目
项目根目录/.meteor/versions文件
发现akryum:vue-component@0.14.3
另一个
通过查看2021年的新创建的项目
项目根目录/.meteor/versions文件
发现akryum:vue-component@0.15.3
结论:是插件版本发生改变了。0.14.3才能搭配1.8.1使用的,若是0.15.3就会报错。因此指定版本安装插件即可。
meteor add akryum:vue-component@=0.14.3
更多cmd命令,可以通过meteor add --help
查看
到此时,在meteor中集成vue框架就成功了。
后面就跟着官网的步骤操作即可。感慨良多!
Integrating Vue With Meteor
To start a new project:
meteor create vue-meteor-app --release 1.8.1
To install Vue in Meteor, you should add it as an npm dependency:
meteor npm install --save vue
To support Vue’s Single File Components with the .vue file extensions, install the following Meteor package created by Vue Core developer Akryum (Guillaume Chau).
meteor add akryum:vue-component
如果项目运行不起来,应该是akryum:vue-component
的版本和项目的版本1.8.1不搭配。
因此要指定akryum:vue-component
的版本安装即可,如下:
meteor add akryum:vue-component@=0.14.3
You will end up with at least 3 files:
- a
/client/App.vue
The root component of your app - a
/client/main.js
Initializing the Vue app in Meteor startup - a
/client/main.html
containing the body with the #app div
We need a base HTML document that has the app
id. If you created a new project from meteor create .
, put this in your /client/main.html
.
<body>
<div id="app"></div>
</body>
You can now start writing .vue files in your app with the following format. If you created a new project from meteor create .
, put this in your /client/App.vue
.
<template>
<div>
<p>This is a Vue component and below is the current date:<br />{{date}}</p>
</div>
</template>
<script>
export default {
data() {
return {
date: new Date(),
};
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
You can render the Vue component hierarchy to the DOM by using the below snippet in you client startup file. If you created a new project from meteor create .
, put this in your /client/main.js
.
import Vue from 'guide/site/content/vue';
import App from './App.vue';
import './main.html';
Meteor.startup(() => {
new Vue({
el: '#app',
App,
});
});
Run your new Vue+Meteor app with this command: NO_HMR=1 meteor
Using Meteor’s data system
One of the biggest advantages of Meteor is definitely it’s realtime data layer. It allows for so called full-stack reactivity and optimistic UI functionality. To accomplish full-stack reactivity, Meteor uses Tracker. In this section we will explain how to integrate Meteor Tracker with Vue to leverage the best of both tools.
- Install the vue-meteor-tracker package from NPM:
meteor npm install --save vue-meteor-tracker
Next, the package needs to be plugged into Vue as a plugin. Add the following to your /client/main.js
:
import Vue from 'vue';
import VueMeteorTracker from 'vue-meteor-tracker'; // import the integration package!
import App from './App.vue';
import './main.html';
Vue.use(VueMeteorTracker); // Add the plugin to Vue!
Meteor.startup(() => {
new Vue({
el: '#app',
App,
});
});
Example app
If you’ve followed the integration guide, then your Vue application shows the time it was loaded.
Let’s add some functionality that makes this part dynamic. To flex Meteor’s plumbing, we’ll create:
- A Meteor Collection called
Time
with a currentTime
doc. - A Meteor Publication called
Time
that sends all documents - A Meteor Method called
UpdateTime
to update the currentTime
doc. - A Meteor Subscription to
Time
- Vue/Meteor Reactivity to update the Vue component
The first 3 steps are basic Meteor:
- In
/imports/collections/Time.js
Time = new Mongo.Collection("time");
- In
/imports/publications/Time.js
Meteor.publish('Time', function () {
return Time.find({});
});
- In
/imports/methods/UpdateTime.js
Meteor.methods({
UpdateTime() {
Time.upsert('currentTime', { $set: { time: new Date() } });
},
});
Now, let’s add these to our server. First remove autopublish so our publications matter:
meteor remove autopublish
For fun, let’s make a settings.json file:
{ "public": { "hello": "world" } }
Now, let’s update our /server/main.js
to use our new stuff:
import { Meteor } from 'meteor/meteor';
import '/imports/collections/Time';
import '/imports/publications/Time';
import '/imports/methods/UpdateTime';
Meteor.startup(() => {
// Update the current time
Meteor.call('UpdateTime');
// Add a new doc on each start.
Time.insert({ time: new Date() });
// Print the current time from the database
console.log(`The time is now ${Time.findOne().time}`);
});
Start your Meteor app, your should see a message pulling data from Mongo. We haven’t made any changes to the client, so you should just see some startup messages.
meteor
- and 5) Great, let’s integrate this with Vue using Vue Meteor Tracker and update our
/client/App.vue
file:
<template>
<div>
<div v-if="!$subReady.Time">Loading</div>
<div v-else>
<p>Hello {{hello}},
<br>The time is now: {{currentTime}}
</p>
<button @click="updateTime">Update Time</button>
<p>Startup times:</p>
<ul>
<li v-for="t in TimeCursor">
{{t.time}} - {{t._id}}
</li>
</ul>
<p>Meteor settings</p>
<pre><code>
{{settings}}
</code></pre>
</div>
</div>
</template>
<script>
import '/imports/collections/Time';
export default {
data() {
console.log('Sending non-Meteor data to Vue component');
return {
hello: 'World',
settings: Meteor.settings.public, // not Meteor reactive
}
},
// Vue Methods
methods: {
updateTime() {
console.log('Calling Meteor Method UpdateTime');
Meteor.call('UpdateTime'); // not Meteor reactive
}
},
// Meteor reactivity
meteor: {
// Subscriptions - Errors not reported spelling and capitalization.
$subscribe: {
'Time': []
},
// A helper function to get the current time
currentTime () {
console.log('Calculating currentTime');
var t = Time.findOne('currentTime') || {};
return t.time;
},
// A Minimongo cursor on the Time collection is added to the Vue instance
TimeCursor () {
// Here you can use Meteor reactive sources like cursors or reactive vars
// as you would in a Blaze template helper
return Time.find({}, {
sort: {time: -1}
})
},
}
}
</script>
<style scoped>
p {
font-size: 2em;
}
</style>
Restart your server to use the settings.json
file.
meteor --settings=settings.json
Then refresh your browser to reload the client.
You should see:
- the current time
- a button to Update the current time
- startup times for the server (added to the Time collection on startup)
- The Meteor settings from your settings file
Excellent! That’s a tour of some of Meteor’s features, and how to integrate with Vue. Have a better approach? Please send a PR.
Style Guide and File Structure
Like code linting and style guides are tools for making code easier and more fun to work with.
These are practical means to practical ends.
- Leverage existing tools
- Leverage existing configurations
Meteor’s style guide and Vue’s style guide can be overlapped like this:
- Configure your Editor
- Configure eslint for Meteor
- Review the Vue Style Guide
- Open up the ESLint rules as needed.
Application Structure is documented here:
- Meteor’s Application Structure is the default start.
- Vuex’s Application Structure may be interesting.
SSR and Code Splitting
Vue has an excellent guide on how to render your Vue application on the server. It includes code splitting, async data fetching and many other practices that are used in most apps that require this.
Basic Example
Making Vue SSR to work with Meteor is not more complex then for example with Express. However instead of defining a wildcard route, Meteor uses its own server-render package that exposes an onPageLoad
function. Every time a call is made to the server side, this function is triggered. This is where we should put our code like how its described on the VueJS SSR Guide.
To add the packages, run:
meteor add server-render
meteor npm install --save vue-server-renderer
then connect to Vue in /server/main.js
:
import { Meteor } from 'meteor/meteor';
import Vue from 'vue';
import { onPageLoad } from 'meteor/server-render';
import { createRenderer } from 'vue-server-renderer';
const renderer = createRenderer();
onPageLoad(sink => {
console.log('onPageLoad');
const url = sink.request.url.path;
const app = new Vue({
data: {
url
},
template: `<div>The visited URL is: {{ url }}</div>`
});
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error');
return
}
console.log('html', html);
sink.renderIntoElementById('app', html);
})
})
Luckily Akryum has us covered and provided us with a Meteor package for this: akryum:vue-ssr allows us to write our server-side code like below:
import { VueSSR } from 'meteor/akryum:vue-ssr';
import createApp from './app';
VueSSR.createApp = function () {
// Initialize the Vue app instance and return the app instance
const { app } = createApp();
return { app };
}
Server-side Routing
Sweet, but most apps have some sort of routing functionality. We can use the VueSSR context parameter for this. It simply passes the Meteor server-render request url which we need to push into our router instance:
import { VueSSR } from 'meteor/akryum:vue-ssr';
import createApp from './app';
VueSSR.createApp = function (context) {
// Initialize the Vue app instance and return the app + router instance
const { app, router } = createApp();
// Set router's location from the context
router.push(context.url);
return { app };
}
更多资料请看meteor官网https://guide.meteor.com/vue.html