Vue + Webpack project practice

Recently, I made some attempts based on Vue + Webpack in the internal project. After discussing with colleagues in a small range, many students still recognized and liked it, so I shared it with more people through blog.

I’ll start with a brief introduction to Vue and Webpack:

(You can skip the first two if you’re already familiar with them.)

Introduce the vue

Vue. Js is a minimalist MVVM framework. If I had to use one word to describe it, it would be “lightweight”. In a single sentence, it encapsulates the best of many good, streamlined front-end frameworks, while keeping it simple and easy to use. Without further ado, let’s look at some examples:

<script src="vue.js"></script> <div id="demo"> {{message}} <input v-model="message"> </div> <script> var vm = new Vue({ el: '#demo', data: { message: 'Hello Vue.js! ' } }) </script>Copy the code

First, the code is divided into two parts, one is HTML, and the other is a view template, which contains a text value of message and an input field with the same value. The other part is script, which creates a VM object where the bound DOM node is #demo and the bound data is {message: ‘Hello vue.js ‘}, the final page display is a piece of Hello vue.js text with an input box containing the same text. More importantly, because the data is bidirectional binding, we modify the text in the text box at the same time, The first text and the value of the message field of the bound data are updated synchronously – and vue.js does all the underlying logic for you.

Tell me a little bit more

We can also add more directives, such as:

<script src="vue.js"></script>

<div id="demo2">
  <img title="{{name}}" alt="{{name}}" v-attr="src: url">
  <input v-model="name">
  <input v-model="url">
</div>

<script>
  var vm = new Vue({
    el: '#demo2',
    data: {
      name: 'taobao',
      url: 'https://www.taobao.com/favicon.ico'
    }
  })
</script>
Copy the code

Here the view template adds a tag, and we see that the values for both properties are {{name}}. In this case, the image’s title and Alt property values are both bound to the string ‘Taobao’.

If you want to bind a feature like img[SRC] that can’t be initialized arbitrarily in HTML (it might default to an unexpected network request), it doesn’t matter. V-attr =” SRC: URL “syncs the URL from the bound data.

There are many functions that have not been introduced, I recommend you to come to my (initiated and) translated vue.js Chinese document

Web componentization

Finally, it introduces the thinking and design of vue. js for web componentization development

If we want to develop larger web pages or Web applications, the idea of web componentization is very important, and it’s a perennial theme throughout the front-end community today.

Vue. Js design a *. Vue format file, make each component of the style, template and script collection into a whole file, each file is a component, but also contains the dependencies between components, although small, the whole component from the appearance, structure, features and dependencies:

And supports precompilation of various dialects:

In this way, no matter how big the system is, the complex interface can be achieved in this way. Of course, this component is written in a way that requires compilation tools to eventually work on the browser side, and a webPack-based solution is described below.

summary

From the perspective of functions, template, directive, data-binding and Components are complete in various practical functions. Advanced functions such as filter, computed Var, VAR watcher and Custom Event are also filled with the author’s clever thinking. From a development experience point of view, these designs are almost completely natural, with no sense of deliberate design or thoughtlessness, and only a few places where you have to bring your own frameworkv-Prefix. In terms of performance and volume, vue.js is also very competitive!

Introduce webpack

Webpack is another good recent discovery. Its main purpose is to use CommonJS syntax to prepare all static resources that need to be published on the browser side, such as resource merging and packaging.

For example, there is now a script main file app.js that relies on another script module.js

// app.js
var module = require('./module.js')
... module.x ...

// module.js
exports.x = ...
Copy the code

With the webpack app.js bundle.js command, app.js and module.js can be packaged together and saved to bundle.js

At the same time webPack provides a powerful loader mechanism and plugin mechanism, loader mechanism supports loading a variety of static resources, not only JS scripts, even HTML, CSS, images and other resources have corresponding Loader to do dependency management and packaging; Plugin can control the whole Webpack process.

For example, after installing and configuring csS-loader and style-loader, you can load a style sheet to a web page by requiring (‘./bootstrap.css’). It’s very convenient.

The idea behind Webpack is to convert all non-JS resources to JS (e.g., converting a CSS file to a “create a style tag and insert it into a document” script, converting an image to a javascript variable or base64 encoding for an image address), Then use CommonJS mechanism to manage it. At the beginning, I personally didn’t like this technical form, but with continuous practice and experience, I gradually got used to it and agreed with it.

Finally, for the vue.js mentioned earlier, the authors also provide one called vue-loaderNPM package, can put the*.vueFiles are converted into Webpack packages and integrated into the entire packaging process. So with vue.js, Webpack and Vue-Loader, it’s natural to try them all together!

Project practice process

Back to business. What I want to share today is based on these two things: vue.js and Webpack, and vue-Loader that connects them together

Vue. Js and provides an example project based on all three. However, our example will be closer to the actual working scene, and at the same time, it is consistent with the characteristics and process of the project summarized by the team.

Directory structure design

  • <components>Component directory, one component at a time.vuefile
    • a.vue
    • b.vue
  • <lib>If you really have code that is not a component, but is not external (TNPM), you can put it here
    • foo.css
    • bar.js
  • <src>Main application/page related files
    • app.htmlThe main HTML
    • app.vueThe vue
    • app.jsThe usual thing to do is justvar Vue = require('vue'); new Vue(require('./app.vue'))
  • <dist> (ignored)
  • <node_modules> (ignored)
  • gulpfile.jsDesign project packaging/monitoring tasks
  • package.jsonRecord basic project information, including module dependencies
  • README.mdProject Introduction

packaging

Gulpfile.js allows you to design a whole webpack-based package/listen/debug task

The official documentation for the gulp-Webpack package recommends this:

var gulp = require('gulp');
var webpack = require('gulp-webpack');
var named = require('vinyl-named');
gulp.task('default', function() {
  return gulp.src(['src/app.js', 'test/test.js'])
    .pipe(named())
    .pipe(webpack())
    .pipe(gulp.dest('dist/'));
});
Copy the code

Let’s make some modifications to this file, first adding vue-loader

tnpm install vue-loader --save

.pipe(webpack({
  module: {
    loaders: [
      { test: /\.vue$/, loader: 'vue'}
    ]
  }
}))
Copy the code

Second, take the list of files to be packaged from gulp.src(…). For future maintenance and the opportunity to share this information with other tasks

var appList = ['main', 'sub1', 'sub2']

gulp.task('default', function() {
  return gulp.src(mapFiles(appList, 'js'))
    ...
})

/**
 * @private
 */
function mapFiles(list, extname) {
  return list.map(function (app) {return 'src/' + app + '.' + extname})
}
Copy the code

Now run gulp and the files should be packaged and generated in the dist directory. Then we add an introduction to these generated JS files in SRC /*.html:

<! DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Main</title> </head> <body> <div id="app"></div> <script src=".. /dist/main.js"></script> </body> </html>Copy the code

Open SRC /main.html in your browser and the page should work properly

Join to monitor

Listening is even easier by adding watch: true to the webpack(opt) argument.

.pipe(webpack({
  module: {
    loaders: [
      { test: /\.vue$/, loader: 'vue'}
    ]
  },
  watch: true
}))
Copy the code

Of course, it is best to design packaging and listening as two tasks, named Bundle and Watch respectively:

gulp.task('bundle', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig())) .pipe(gulp.dest('dist/')) }) gulp.task('watch', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig({watch: true}))) .pipe(gulp.dest('dist/')) }) /** * @private */ function getConfig(opt) { var config = { module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] } } if (! opt) { return config } for (var i in opt) { config[i] = opt } return config }Copy the code

Now you don’t have to run gulp bundle every time you change a file to see the latest results, you can just refresh the browser after each change.

debugging

Packaged code is less readable, and debugging directly on such code is still less convenient. At this point, WebPack + Vue has another thing ready to go: Source Map support. Devtool: ‘source-map’ :

var config = { module: { loaders: [ { test: /.vue$/, loader: ‘vue’} ] }, devtool: ‘source-map’ }

Run gulp bundle or gulp Watch again to see if you can trace breakpoints to source code when debugging in developer tools:

The complete javascript code is as follows:

var gulp = require('gulp') var webpack = require('gulp-webpack') var named = require('vinyl-named') var appList = ['main'] gulp.task('default', ['bundle'], function() { console.log('done') }) gulp.task('bundle', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig())) .pipe(gulp.dest('dist/')) }) gulp.task('watch', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig({watch: true}))) .pipe(gulp.dest('dist/')) }) /** * @private */ function getConfig(opt) { var config = { module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] }, devtool: 'source-map' } if (! opt) { return config } for (var i in opt) { config[i] = opt[i] } return config } /** * @private */ function mapFiles(list, extname) { return list.map(function (app) {return 'src/' + app + '.' + extname}) }Copy the code

In the end, violet is better than Dulla

Create a generator for VUE + Webpack and share the project experience with more people. I currently wrote a paper called “Scaffolding” based on lightweight scaffolding tools that the team uses internallyjust-vueAt present, this generator is still in a small range of trial, to be more mature, and then share

conclusion

In fact, the just-Vue scaffolding mentioned above is much more than what is introduced in the article. We have done more precipitation and accumulation in the “last kilometer” of business landing. For example, automatic picture uploading and picture quality processing, REM unit automatic conversion, server/client/data interface combing and integration, automatic HTMLOne packaging and AWP release, etc. They provide a simpler and more efficient work experience for the developers who support the business. Space is limited, but I hope to share more in the future.

Finally, I hope you can come and play if you are interested. I am willing to provide one-to-one introductory instruction for all students in the wireless front-end group

Just the Vue!