Build a simple vue development environment based on Web pack from scratch

Keywords: Vue Webpack npm sass

It's 8102. Now I'm going to talk about the configuration of webpack. Well, it's a bit late. Moreover, the project generated based on vue-cli or create-react-app has already configured webpack for us with one key, which does not seem to require our in-depth understanding.

However, it is necessary to build a simple development environment from scratch in order to learn and understand what pain webpack has solved in the front end. The web pack configuration in this article refers to the web pack-simple template provided by vue-cli, which is the simplest web pack configuration in vue-cli and is very suitable for learning from scratch.

Note: This web pack is based on 3.10.0, part of the content of Web Pack 4 may no longer apply!!!

Demo Code Download

Install webpack

npm i webpack -g

webpack4 also needs to be installed separately

npm i webpack-cli -g

Project Initialization

Create a new folder vue-webpack-simple

New package.json

npm init -y

Install vue webpack webpack-dev-server

npm i vue --save
npm i webpack webpack-dev-server --save-dev

New index.html under the root directory

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

New webpack.config.js under the root directory

var path = require('path');
var webpack = require('webpack');

module.exports = {};

New src folder, new main.js under src folder

At present, the structure of the whole project is as follows:

js modularization

Before ES6 came into being, there was no unified module system for js.
The server side uses the CommonJS specification, while the browser side has two specifications, AMD and CMD.

The idea of webpack is that everything is modular. The official recommendation is to use the commonJS specification, which makes it possible for browsers to use the modular writing of commonJS.

module.exports = {}

Create a new util.js under src directory

module.exports = function say() {
    console.log('hello world');
}

main.js

var say = require('./util');
say();

Modify webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js', // The entry file for the project, webpack starts with main.js and loads and packages all dependent js
    output: {
        path: path.resolve(__dirname, './dist'), // Packing file path for project
        publicPath: '/dist/', // Access paths through devServer
        filename: 'build.js' // Packed file name
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    }
};

Modify package.josn

"scripts": {
    "dev": "webpack-dev-server --open --hot",
    "build": "webpack --progress --hide-modules"
  },

Note: webpack-dev-server automatically starts a static resource web server -- the hot parameter indicates that hot updates are started

Modify index.html to introduce packaged files

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script src="/dist/build.js"></script>
</body>

</html>

Function

npm run dev

You can find a page that the browser opens automatically. Look at the console. hello world typed it out.

We can modify util.js at will, and we can find that the browser will refresh automatically, which is very convenient.

If we want to see the packaged bundle.js file, run

npm run build

You can see that a dist directory has been generated with packaged bundles. JS in it

By default, webpack does not support transcoding es6, but import export is supported separately. So we can rewrite the previous modular writing

util.js

export default function say() {
    console.log('hello world ');
}

main.js

import say from './util';

say();

Introducing vue

Let's try to introduce Vue (single file. Vue is not considered at present)

main.js

import Vue from 'vue';

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
});

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        {{message}}
    </div>
    <script src="/dist/build.js"></script>
    
</body>

</html>

Also note that you need to modify the webpack.config.js file

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'build.js'
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }
};

Rerun npm run dev and you can see that Hello World is normally displayed on the page

Introducing scss and css

webpack only supports js modularization by default, and if you need to introduce other files as modules, you need the corresponding loader parser

npm i node-sass css-loader vue-style-loader sass-loader --save-dev

webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'build.js'
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ],
            }
        ]
    }
};

Interpretation:

{
    test: /\.css$/,
    use: [
        'vue-style-loader',
        'css-loader'
    ],
}

This code means: match the file with the suffix css, and then use css-loader, vue-style-loader to parse it.
The parser execution sequence is from bottom to top (first css-loader and then vue-style-loader)

Note: Because we are developing with Vue here, we use vue-style-loader and style-loader in other cases.

 

css-loader allows us to introduce css in a modular way, and vue-style-loader inserts the introduced css into the style tag on the html page

To introduce scss is also the same configuration.

module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.scss$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader'
                ],
            },
            {
                test: /\.sass$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader?indentedSyntax'
                ],
            }]
    }

Let's try it now.
Create a new style directory in the src directory and a new common.scss in the style directory

body {
    background: #fed;
}

main.js

import './style/common.scss';

Find css style useful

Using babel transcoding

ES6 grammar is still not supported by most browsers. bable can transcode ES6 into ES5 grammar, so that we can boldly use the latest features in our project.

npm i babel-core babel-loader babel-preset-env babel-preset-stage-3 --save-dev

Create a new. babelrc file in the project root directory

{
  "presets": [
    ["env", { "modules": false }],
    "stage-3"
  ]
}

webpack.config.js adds a loader

{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/
}

exclude means ignoring files under the node_modules folder without transcoding

Now let's try the async await grammar.
util.js

export default function getData() {
    return new Promise((resolve, reject) => {
        resolve('ok');
    })
}

main.js

import getData from './util';
import Vue from 'vue';

import './style/common.scss';

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  methods: {
    async fetchData() {
      const data = await getData();
      this.message = data;
    }
  },
  created() {
    this.fetchData();
  }
});

At this point, the console will report an error regenerator Runtime is not defined because we did not install babel-polyfill.

npm i babel-polyfill --save-dev

Then modify the entry to webpack.config.js

entry: ['babel-polyfill', './src/main.js'],

Re-npm run dev, you can find the normal operation

Introducing Photo Resources

Introduce pictures as modules

npm i file-loader --save-dev

webpack.config.js adds a loader

{
    test: /\.(png|jpg|gif|svg)$/,
    loader: 'file-loader',
    options: {
        name: '[name].[ext]?[hash]'
    }
}

Create a new img directory under src directory and store a picture logo.png

Modify main.js

import getData from './util';
import Vue from 'vue';

import './style/common.scss';


Vue.component('my-component', {
  template: '<img :src="url" />',
  data() {
    return {
      url: require('./img/logo.png')
    }
  }
})

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue !'
  },
  methods: {
    async fetchData() {
      const data = await getData();
      this.message = data;
    }
  },
  created() {
    this.fetchData()
  }
});

Modify index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        {{message}}
        <my-component/>
    </div>
    <script src="/dist/build.js"></script>
    
</body>

</html>

As you can see, the pictures were loaded correctly.

Single file component

In the previous example, we used Vue.component to define global components
In practical projects, single file components are more recommended.

npm i vue-loader vue-template-compiler --save-dev

Add a loader

{
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
        loaders: {
            'scss': [
                'vue-style-loader',
                'css-loader',
                'sass-loader'
            ],
            'sass': [
                'vue-style-loader',
                'css-loader',
                'sass-loader?indentedSyntax'
            ]
        }
    }
}

Create a new App.vue in the src directory

<template>
  <div id="app">
    <h1>{{ msg }}</h1>
    <img src="./img/logo.png">
    <input type="text" v-model="msg">
  </div>
</template>

<script>

import getData from './util';

export default {
  name: 'app',
  data () {
    return {
      msg: 'Welcome to Your Vue.js'
    }
  },
  created() {
    this.fetchData();
  },
  methods: {
     async fetchData() {
      const data = await getData();
      this.msg = data;
    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;

  h1 {
    color: green;
  }
}
</style>

main.js

import Vue from 'vue';
import App from './App.vue';

import './style/common.scss';

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
</body>

</html>

npm run dev, you can find that the single file is loaded correctly

source-map

In the development phase, debugging is also a very important requirement.

App.vue

created() {
    this.fetchData();
    console.log('23333');
}

We deliberately called a console and opened the console.

We Click to enter the console's detailed address

It's packaged build.js, and I don't know which component it was written in, which makes debugging difficult.

Modify webpack.config.js

module.exports = {
    entry: ['babel-polyfill', './src/main.js'],
    // Elimination of other ____________.

    devtool: '#eval-source-map'
};

Re-npm run dev

This debugging, it directly returns to the source code of that component, this is not packaged!

Package release

Let's try npm run build to package the files first.

You will find that the packaged build.js is very large, more than 500 k

In actual publishing, files will be compressed, cached, segregated, and so on.

npm i cross-env --save-dev

Modify package.json

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
}

This time we set up the environment variable, when packaging, NODE_ENV is production.

Then modify webpack.config.js to compress js code when NODE_ENV is production

var path = require('path');
var webpack = require('webpack');

module.exports = {
    // Omission...
}

if (process.env.NODE_ENV === 'production') {
    module.exports.devtool = '#source-map';
    module.exports.plugins = (module.exports.plugins || []).concat([
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: '"production"'
        }
      }),
      new webpack.optimize.UglifyJsPlugin(),
    ])
  }
  

repackaging

As you can see, the compression effect is very obvious!

So far, a very simple vue development environment has been successfully built.

Note: There are many other configurations that can be optimized in this article, such as separating js from css

Readers can learn about it on their own, but here's just a guide to the most basic web pack configuration.

 

Change from: https://segmentfault.com/a/1190000012789253?utm_source=tag-newest

Posted by ChetUbetcha on Sun, 05 May 2019 22:45:38 -0700