Vue.js¶
Vue.js is an open-source JavaScript component-based framework that makes it easy to develop reactive applications.
Here you will find some guidelines explaining how you have to proceed to build up you application.
Before beginning¶
Vue.js can be used along with some additional libraries like VueX or Vue-router. To know when you have to use these libraries, here is a table that will help you to decide:
Your app |
Which lib should I use? |
---|---|
Has a component with few responsibilities |
Vue.js |
Is medium-sized and has complex workflows |
Vue.js + Vuex |
Has several pages to display |
Vue.js + Vuex + Vue-router |
Note
We strongly suggest you to install the vue-devtools browser extension. It provides nice features that ease the development of your applications.
Folder structure of a Vue application¶
A Vue app has to be split out in distinct parts.
Here is the folder structure you have to follow:
my-plugin/
|-- build-manifest.json # Edit it to declare your app for the build system and for translations
|-- scripts/
|-- my-vue-app/
|-- po/ # Localization strings
|-- src/ # The app source-code
|-- api/ # REST API consumers
|-- components/ # Vue components
|-- MyFeature/
`-- OtherFeature/
|-- store/ # Vuex store modules (actions/mutations/getters)
|-- router/ # Vue-router modules
|-- index.ts # App bootstrapping
|-- jest.config.js # Unit tests bootstrapping
|-- package.json # Declares the App, its dependencies and its build script.
|-- package-lock.json # Generated by npm. Never edit manually.
|-- tsconfig.json # Typescript configuration
`-- webpack.config.js # Webpack configuration to build the App
Build your Vue application¶
The build system will read build-manifest.json
to understand where it needs to run npm install
and npm run build
.
// tuleap/plugins/my-plugin/build-manifest.json
{
"name": "my-plugin",
"components": [
"scripts/"
],
"gettext-vue": {
"my-vue-app": {
"src": "scripts/my-vue-app/src",
"po": "scripts/my-vue-app/po"
}
}
}
To build up your application, you will have to update or create a webpack.config.js
file.
This file should be located in my-plugin/scripts/
.
// tuleap/plugins/my-plugin/scripts/webpack.config.js
const path = require("path");
const webpack_configurator = require("../../../tools/utils/scripts/webpack-configurator.js");
const assets_dir_path = path.resolve(__dirname, "./assets");
const webpack_config_for_my_awesome_vue_app = {
entry: {
"my-vue-app": "./my-vue-app/src/index.ts"
},
context: path.resolve(__dirname),
output: webpack_configurator.configureOutput(assets_dir_path),
externals: {
tlp: "tlp"
},
module: {
rules: [
...webpack_configurator.configureTypescriptRules(webpack_configurator.babel_options_ie11),
webpack_configurator.rule_easygettext_loader,
webpack_configurator.rule_vue_loader
]
},
plugins: [webpack_configurator.getManifestPlugin(), webpack_configurator.getVueLoaderPlugin()],
resolveLoader: {
alias: webpack_configurator.easygettext_loader_alias
}
};
module.exports = webpack_config_for_my_awesome_vue_app;
Once you have a webpack config, you will need a package.json
in my-plugin/scripts/
.
// tuleap/plugins/my-plugin/scripts/package.json
{
"author": "you",
"name": "my-vue-app",
"version": "0.0.1",
"private": true,
"dependencies": {
"vue": "^2.6.10",
"vue-gettext": "^2.1.0",
"vuex": "^3.1.1"
},
"devDependencies": {},
"config": {
"bin": "../../../../node_modules/.bin" // This should point to the node_modules/.bin folder in tuleap/ root folder
},
"scripts": {
"build": "NODE_ENV=production $npm_package_config_bin/webpack --mode=production",
"watch": "NODE_ENV=watch $npm_package_config_bin/concurrently --raw --kill-others '$npm_package_config_bin/webpack --watch --mode=development' 'CI=true npm test -- --watch'",
"test": "$npm_package_config_bin/jest"
}
}
Note
All the development dependencies are available at the tuleap root, hence the config.bin
.
Use the npm scripts to build up the application or to launch the unit tests.
npm run build # For a production build, outputs minified code.
npm run watch # Run the :ref:`Jest <jest_unit_test>` unit tests and build the app in watch mode at the same time.
npm run test # Run the :ref:`Jest <jest_unit_test>` unit tests only once.
Once you have a package.json
file, you will also need a tsconfig.json
file to configure Typescript.
// tuleap/plugins/my-plugin/scripts/tsconfig.json
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"module": "es2015" //redefine otherwise vue-jest crashes: https://github.com/vuejs/vue-jest/issues/144
},
"include": [
"my-vue-app/**/*"
],
"exclude": [
"node_modules",
"my-vue-app/**/*.test.ts"
]
}
Bootstrap your application¶
This section will explain you how to properly integrate your application in Tuleap.
Create a mount point¶
To allow your app to run in Tuleap, you may need to create a mount point in a mustache template.
Your mount point needs to have a unique identifier in order to be easily retrieved from the DOM.
This is also the place where you can pass some data from PHP to JavaScript via data-*
attributes:
<div class="tlp-pane">
<div id="my-vue-app-mount-point"
data-user="{{ user }}"
></div>
</div>
Once your mount point is ready, head to your index.ts
file.
// tuleap/plugins/my-plugin/scripts/<my_vue_app>/src/index.ts
import Vue from 'vue';
import MyVueApp from './components/MyVueApp.vue';
document.addEventListener('DOMContentLoaded', () => {
// Retrieve the mount point from the DOM
const vue_mount_point_id = "my-vue-app-mount-point";
const vue_mount_point = document.getElementById(vue_mount_point_id);
if (!vue_mount_point) {
throw new Error(`Could not find Vue mount point ${vue_mount_point_id}`);
}
const MyVueAppComponent = Vue.extend(MyVueApp);
new MyVueAppComponent({ // Create a new component
propsData: {
user: JSON.parse(vue_mount_point.dataset.user) // Pass the data bound to the mount point to the app
}
}).$mount(vue_mount_point); // Mount the app on the moint point
});
Vue and Typescript¶
The reference language to use with Vue.js is now Typescript.
Best-practices for Tuleap¶
When you submit a patch for review, we may request changes to better match the following best practices. Please try to follow them. Many rules are already enforced by the pre-commit hook that runs eslint with eslint-plugin-vue.
Please avoid the usage of vue directives shorthands. Shorthands are nice to use but it is not obvious for the others to figure out which directive you are actually using.
Always use
PascalCase
for component names.Always use multi-word names for components, for example: “DocumentSearch”. In templates, this translates as
<document-search/>
. See the dedicated Vue Style Guide rule.Always use
snake_case
for computed properties. I know, there are parentheses when we define them, but they really are properties, not methods. See Tuleap coding standards.Always use
snake_case
for props. They follow the same rule as variables.Always use
camelCase
for methods.Always use
snake_case
for Vuex State properties and Getters. They are properties too.Always use
camelCase
for Vuex Mutations and Actions. They are methods.Always name files and folders inside
components/
withPascalCase
(just like component names).Always name javascript files (in all other folders) with
dash-case
.Avoid having too many components that depend on
this.$route
. Inject what you need via props instead.Always use named exports in Vuex Getters, Mutations and Actions. Default export may be used for State definition. Named exports make it easier to import only what we want.
Always use the inline export syntax
export function myAction()
orexport const myMutation() => {}
. It makes it easy to add “private” (non-exported) functions that will be reused.
Resources¶
Vue.js doc: https://vuejs.org/v2/guide/
Vuex doc: https://vuex.vuejs.org/
Vue-router doc: https://router.vuejs.org/
Vue.js Official Style Guide: https://vuejs.org/v2/style-guide/
eslint-plugin-vue’s rules: https://vuejs.github.io/eslint-plugin-vue/rules/
TypeScript reference: https://www.typescriptlang.org
vue-gettext: https://github.com/Polyconseil/vue-gettext