The introduction

This is the author’s webpack configuration related first article, so this length may be a little long, if you can patiently read it, I believe that there will be a certain harvest for you, for everyone big guy, if you see the words in this article, or the idea of thinking is not correct, I hope to comment and teach me, thank you ~

start

Creating a folder

To create a folder to support our scaffolding, type mkdir webpack4-vue on the command line to create the folder, and then CD webpack4-vue to enter the file. For Windows, cheer yourself up.

After completing the configuration, we will get a packjson.json file, which looks like this:

{
  "name": "webpack4-vue"."version": "1.0.0"."description": "A simple DEMO, using WebPack4 to configure a vue scaffolding"."main": "index.js"."scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "fyfy"."license": "ISC"
}
Copy the code

webpack

The first step is to introduce Webpack. According to the official document, we need to install Webpack and webpack-CLI respectively

npm install --save-dev webpack
npm install --save-dev webpack-cli
Copy the code

After successfully installing the dependencies, we will first create a simple configuration file webpack.config.js

module.exports = {
  // Indicates the development mode
  mode: 'development'.// The entry to the file (that is, the file we want to pack)
  entry: path.resolve(__dirname, './src/main.js'),
  // The exit of the file is the file we want to generate
  output: {
    // Where [name] is an entry name
    filename: '[name].js'.path: path.resolve(__dirname, './dist')}}Copy the code

After the configuration file is written, we need to add the following command in packjson.json, which means to use the config configuration file to complete the subsequent webpack packing. For more details about cli, you can click here to view the document

{..."scripts": {
  	// Add a package command
    "build": "webpack --config webpack.config.js"."test": "echo \"Error: no test specified\" && exit 1"},... }Copy the code

Next we create the/SRC /main.js file and write the following

import Vue from 'vue'

new Vue({
  el: '#app'.template: `<div>{{text}}</div>`.data() {
    return {
      text: 'hello webpack4 - vue'}}})Copy the code

NPM install vue is a dependency on NPM install vue. Then we create an index. HTML file in the following folder and write the following contents

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

Then runnpm run build“> < div style =” max-width: 100%; clear: bothAfter a search in Vue’s official documentation, we found the following resultsnode_modules/vue/package.jsonIf you look down here

{..."main": "dist/vue.runtime.common.js"."module": "dist/vue.runtime.esm.js". }Copy the code

And then we see over heremodulewithmainTwo fields (why to see two different fields, interested partners can be baidu ha) exposed package arevue.runtime.**.jsWe are comingVue official documentFound in theInstallation – An explanation of the different buildsThis table ofThe conclusion is that the current default exposed version of the NPM package isOnly the running version is includedThis version is similar toThe full versionWhat is the difference between?So obviously we haven’t introduced it yetvue-loaderOr is itvueify, so based on the conclusion of the document we want ourmain.jsCode can be executed in. In our current situation, we have to introduce the full versionwebpack.config.jsTo add the following configuration items

// ...
resolve: {
  alias: {
    'vue$': 'vue/dist/vue.esm.js'}}// ...
Copy the code

Then run our package command againnpm run build, double-click to open the packageindex.htmlViewing web pagesNice! Here we have completed the most simple vUE “Webpack scaffolding tool” ~

babel-loader

Now that we have our first version out, let’s go ahead and install x using the current most popular ES6. However, in the case of ES6, we need to consider the compatibility of our X. Const const const const const const const const const const const

OK! Our IE is messing up again, so what do we do? ES6 and beyond? This is definitely not possible, and this is where the Babel tool chain comes in.

Babel

First, let’s take a look at what Babel is. Let’s take a look at the official description

The introduction has been relatively clear, equivalent to theES6And above convert toES5orES3The content of the. At present, after the next search and learning, the main nouns will be listed below

  • @babel/polyfill
  • @babel/preset-env
  • @babel/core
  • babel-loader

Let’s take a look at the specific functions and the advantages and disadvantages of multiple tools when they can be used together

@babel/polyfill

The official documentation is quite straightforward in its support, stating that using @babel/ Polyfill is basically equivalent to the following code snippet

import 'core-js/stable';
import 'regenerator-runtime/runtime';
Copy the code

What does core-JS and Regenerator-Runtime do


core-js

Github address: github.com/zloirock/co…

From the github introduction, we can roughly infer that this library is a collection of all the shim we currently support with Babel, and what we can tell is, Currently @babel/polyfill, @babel/preset-env, @babel/ Preset/Runtime are all closely associated with this library.

If we wanted to go further with polyfill, we would have to go in and see what shims the bottom stable gave us to use, but humans are lazy by nature

Then I found This in the official document of @babel/ Polyfill: This will emulate a full ES2015+ environment (no < Stage 4 proposals) and is intended to be used in an application rather than a library/tool. I can only understand that there will be no pad implementations smaller than Stage 4 proposals. Here we have to mention another knowledge point, that is the formulation process of ES we use, the following will briefly introduce a general process and stage, you do not spray ~

Standards like EcmaScript that we currently use are discussed and specified by the TC39 group. So there are several stages in the formulation process

  • Stage 0 – Hypothesis (Strawman) : Just an idea, maybe a Babel plugin.
  • Stage 1 – Proposal: This is worth following up on.
  • Stage 2 – Draft: Initial specification.
  • Stage 3 – Candidate: Complete the specification and implement it preliminarily on the browser.
  • Stage 4 – Finished: Will be added to the next annual release.

So what we’ve seen at Stage4 is that it’s basically, it’s definitely a standard that’s going to be released this year. We found a collection of this stage on Github. I won’t show you what it contains, but you can click here to learn for yourself. So that’s it for core-JS

regenerator-runtime

Github address: github.com/facebook/re…

(github) — This is a Facebook gasket that supports generators/yield support in ES5


So pick it up here and continue the conversation@babel/polyfillSince it already provides these more mature standards, can we directly use it to provide us with this transformation service?Since we are in the webpack environment, we only see the description of webpack, which basically means that Babel is still recommended for us to use@babel/polyfillCame with the@babel/preset-envIn the process of using together, it will be based onuseBuiltInsField parameters that require different configurations (three different cases are listed).

It’s fine if you don’t use it with @babel/preset-env, but it’s highly recommended.

I’m a rebel and I’d love to know why I can’t play this way, but let’s be patient and watch @babel/ PRESET -env before YY

@babel/preset-env

According to the official documentation for @babel/preset-env, it is used to determine whether a new specification in part of the code needs shims based on the configured runtime environment. Based on this paragraph and the part @babel/polyfill just mentioned, it can be roughly inferred that if @babel/polyfill is directly used, some standard syntax supported by this environment will be replaced by gasket, which will make the volume of the whole package much larger.

After I look at @babel/preset-env, I think the main focus will be on configuration, and we’ll focus on the next section first, and usage aspects will be included in the final “one-two punch”

Configuration items

  • target

Target is a configuration item based on what environment you want your project to run in

  {
    "targets": "> 0.25%, not dead." "
  }
Copy the code

Is not feeling quite semantic words, even do not know how to start, ha ha ha. I did the same, so I found a complete list of configurations on Github at Browserslist, and we just needed to configure it according to our own needs

  • useBuiltIns

useBuiltInsThis property has to do with packaging, first of all it has three values"usage" | "entry" | falseThe default isfalseIf you are usingentryThen you need to import it at your file entrycore-jsOr is it@babel/polyfill“, and it will automatically type in the required packets at the entrance according to your target environment The above two pictures areuseBuiltIns: "entry"In the case of targeting different browser environments, it may be packaged out of a result, then targetingusageWhat is the situation? According to the official case and the statement andentryThe difference is that it determines which files in your development process use the syntax that needs to be supported by shims, and then provides support for the syntaxA file is introduced only once for the same shim This is really nice! Finally, let’s seefalseThe performance of this configuration, the official website documentation says, if yesfalseYou’re not gonna help us deal with itimport "core-js" or import "@babel/polyfill"In fact, WHAT I do not understand is whether it does not help me with processing at all, or whether it just does not deal with the two gasket libraries we introduced. We can try to find out which case in the follow-up experiment.

  • corejs

Make the corresponding core-js version, this know ok ~

Preset -env we know this, let’s go down now

@babel/core

I’m not sure I can explain this to you in a light language like the one above, but I hope you can check out the official documentation below and search for knowledge about AST(abstract syntax tree). You don’t have to be proficient in AST to read this article. I understand that this plugin is used to handle the conversion between JS source code and AST.

babel-loader

I’m sure you’ll say the name has something to do with Webpack. Hahahahaha, that’s right! There may be some guys who don’t know much about webpack. Why do you know the name is related to Webpack?

First, WebPack has four core concepts

  • entry
  • output
  • loader
  • plugins

We have touched on entry and output before, which roughly means the import file and output file we package. Then what is loader? Webpack itself has only js capabilities, so loader is used to convert non-JS files into JS that WebPack can process. Plugins can be used to extend more functionality, such as compression, optimization, file manipulation, and so on.

The babel-loader is obviously designed to handle the new standard ES syntax in files and provide it to WebPack for packaging. This package allows transpiling JavaScript files using Babel and Webpack,ok. Now we know how to use Babel in our scaffolding

Configure the Babel

Let’s take a look at NPM /babel-loader and Babel /webpack. First let’s configure it according to the consistent parts and install the necessary dependencies first

npm install -D babel-loader @babel/core @babel/preset-env webpack
Copy the code

We then added the following configuration information to the webpack.config.js file that we tried to configure according to the configuration in NPM /babel-loader

  // ...
  module: {
    rules: [{test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader'.options: {
            presets: ['@babel/preset-env'}}}]}// ...
Copy the code

Then we modify/SRC /main.js

import Vue from 'vue'

const text = 'hello webpack4 - vue'

class MyClass {
  constructor () {
    console.log('myClass')}}const isHadWebpack = text.includes('webpack')

new Vue({ 
  el: '#app'.template: `<div>{{text}}</div>`,
  data () {
    return {
      text,
      myClass: new MyClass(),
      isHadWebpack
    }
  }
})
Copy the code

The NPM run build command is used to test the package. Let’s take a look at the packaged file

var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! vue */ "./node_modules/vue/dist/vue.esm.js");

function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}

var text = 'hello webpack4 - vue';
var MyClass = function MyClass() {
    _classCallCheck(this, MyClass);
    console.log('myClass');
};

var isHadWebpack = text.includes('webpack');
new vue__WEBPACK_IMPORTED_MODULE_0__["default"] ({el: '#app'.template: "<div>{{text}}</div>".data: function data() {
    return {
      text: text,
      myClass: new MyClass(),
      isHadWebpack: isHadWebpack }; }});Copy the code

As you can see, exceptString.prototype.includes(...)All other methods are converted by shippers. Why not include or shippers? This is because in@babel/polyfillThere is a sentence in the bookSo what that means is that if we’re going to use this globally scoped method that’s mounted on a prototype, we’re going to have to support either polyfill or core-JS that we mentioned earlier, so let’s try core-JS in this case

First pull dependency NPM install core-js-s and then change the configuration of env corresponding to webpack

 // ...
  module: {
    rules: [{test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader'.options: {
            presets: [['@babel/preset-env',
                {
                  useBuiltIns: "usage".// Use it before importing it
                  corejs: 3             // Specify the version number}]}}}]}// ...
Copy the code

Run the command based on the current configuration. The result is as follows

__webpack_require__.r(__webpack_exports__);
/* harmony import */ var core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! core-js/modules/es.string.includes */ "./node_modules/core-js/modules/es.string.includes.js");
/* harmony import */ var core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! vue */ "./node_modules/vue/dist/vue.esm.js");


function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}var text = 'hello webpack4 - vue';

var MyClass = function MyClass() {
    _classCallCheck(this, MyClass);

  console.log('myClass');
};

var isHadWebpack = text.includes('webpack');
new vue__WEBPACK_IMPORTED_MODULE_1__["default"] ({el: '#app'.template: "<div>{{text}}</div>".data: function data() {
    return {
      text: text,
      myClass: new MyClass(),
      isHadWebpack: isHadWebpack }; }});Copy the code

This time you can see that our includes is also supported, but! Or not satisfied, because of such support naked exposure in the global, if there is a tripartite library or is a little brother, he also wrote a global this, that not covered it? How do you do that? Don’t panic! This problem can actually be solved by using @babel/ plugin-transform-Runtime. First let’s install the dependency

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime-corejs3
Copy the code

Then modify module.rules in webpack.config.js

  module: {
    rules: [{test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader'.options: {
            presets: [['@babel/preset-env',
                {
                  useBuiltIns: "usage".// Use it before importing it
                  corejs: 3             // Specify the version number}]],plugins: [["@babel/plugin-transform-runtime", 
                {
                  corejs: 3            // Specify the version number}]}}}]}Copy the code

And then when we run the package command we get

/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! @babel/runtime-corejs3/core-js-stable/instance/includes */ "./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js");
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! @babel/runtime-corejs3/helpers/classCallCheck */ "./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js");
/* harmony import */ var _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/ *! vue */ "./node_modules/vue/dist/vue.esm.js");

var text = 'hello webpack4 - vue';

var MyClass = function MyClass() {
    _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1___default()(this, MyClass);
  
    console.log('myClass');
};

var isHadWebpack = _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default()(text).call(text, 'webpack');

new vue__WEBPACK_IMPORTED_MODULE_2__["default"] ({el: '#app'.template: "<div>{{text}}</div>".data: function data() {
      return {
        text: text,
        myClass: new MyClass(),
        isHadWebpack: isHadWebpack }; }});Copy the code

After this can be really very nice! First we include (…) This is a local method, and another class declaration is extracted, which is quite good. Now that we have the basic configuration of Babel, we can look at something else.

vue-loader

Those of you who use vue scaffolding know that we use **. Vue files for component development and page development, so let’s write a simple vue file

First we create the app. vue file under/SRC and write the following

<template>
  <div>{{text}}</div>
</template>

<script>
export default {
  name: 'App'
}
</script>
Copy the code

/ SRC /main.js is modified as follows

import Vue from 'vue'
import App from './app.vue'
const text = 'hello webpack4 - vue'

class MyClass {
  constructor () {
    console.log('myClass')}}const isHadWebpack = text.includes('webpack')

new Vue({ 
  el: '#app'.components: {
    App
  },
  template: '<App/>',
  data () {
    return {
      text,
      myClass: new MyClass(),
      isHadWebpack,
    }
  }
})
Copy the code

Then we try to pack and see ~Obviously, it is because we have not configured the relevant loader, so let’s have a lookVue official documentWhat does it sayThe account*.vueFiles need to bevue-loaderorvueifyVueify is primarily for Browserify and Vue-Loader is for WebPack, so let’s see how vueify installs and configures vue-Loader.

According to the official instructions, we first complete the most basic dependency installation, and configuration (I will not repeat the introduction here).

I found an error after downloading it according to the instructions on the official website. I checked it and found that I only needed to synchronize the VUE with the VUe-template-Compiler version. After the synchronization, I could basically package it successfully!!

** Note: if you add csS-loader according to the official website, however, if you install CSS-Loader version 4.* then I recommend you to read this issuse **

Ok, so now we can write our Vue component just like our normal SFC

url-loader vs file-loader

In our actual project development process, we often refer to some resources, such as images, GIfs, we are looking at the combination of this kind of resources and webpack related articles. In fact, we will see online articles often mention urL-loader and file-loader related introduction, so I will not go into the details here

The document

  • url-loader
  • file-loader

In this case, we can directly use url-loader to convert DataURL to DataURL. In this case, we can directly use url-loader to convert DataURL to DataURL. NPM install -d file-loader url-loader

webpack.config.js

const kb = 1024
// module.rules. {test: /\.(png|jpg|jpeg|gif)$/i,
    use: [
      {
        loader: 'url-loader'.options: {
          limit: 10 * kb,
        },
      },
    ],
  }
  ...
Copy the code

Create your SRC/Assets folder and put your favorite photo in it. Then modify the code in the app. vue file

<template>
  <div class="red">
    <span>{{text}}</span>
    <img src="(The address of the image you like should be at least in the SRC directory file)" alt="" />
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      text: '123'}}}</script>

<style lang="scss" scoped>
  .red{
    color: red;
  }
</style>
Copy the code

After configuration we try to packagenpm run buildAfter packing, we added a favorite image to our boring dist file ~ but when we opened index.html, we could not see the image. When you opened the console, you would find a similar errorAfter a search, found another similar configurationcss-loader 4.* To solve the configuration problem, add the following configuration to url-loader

. {test: /\.(png|jpg|jpeg|gif)$/i,
  use: [
    {
      loader: 'url-loader'.options: {
        limit: 10 * kb,
        name: 'images/[name].[hash:7].[ext]'.publicPath: '/'.esModule: false},},],}...Copy the code

Then we moved the HTML file in our root directory to the dist folder, and modified the file reference path in the HTML. We verified the packing based on this. Then we repacked the HTML file, and clicked open the HTML file, and we could see the small image we likedWe have already encountered two configuration problems with this esModule, so we will first see what this configuration does, let’s go to file-loader github to see ~The new version of file-loader has adopted ES Modules as the default import mode, so it is possible to import content in the form of an Object, which is a toString content[Object Module]In this form, it will become like this, so we should pay more attention to this when introducing loader again in the future

clean-webpack-plugin

If we check the folder of our DIST, we will find an extra picture. Why is it so? In fact, webpack will not automatically help us to clear the corresponding folder (dist) in each packaging process. At this time, we need to use the ability of plugin because this is not a problem that loader can solve. Because the loader is mainly to solve is a other types (such as PNG | es6 | TS) types of files need to introduce processing into webpack can deal with js. The plugin itself can expand a lot of capabilities ~! How about using the clean-webpack-plugin

First install dependencies

npm install --save-dev clean-webpack-plugin
Copy the code

webpack.config.js

// Import plug-ins
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// ...
plugins: [
/ /... Other plug-ins
	new CleanWebpackPlugin()
]
/ /...
Copy the code

After re-running the package command, we found that some of the redundant files were deleted, leaving only our target package content, but! And then there’s another problem, which is the dist file that we put in before and the HTML file is removed, which we don’t want to see, so let’s see how we can fix that!

html-webpack-plugin

First of all, based on the official document, we learned that this plugin is mainly provide a quickly create HTML in webpack bundles of such a plug-in, then this plugin degrees of freedom, or higher, we can see the configuration items or offers many options can be used, including a series of related hooks to other plug-ins ~

First we install dependencies

npm i --save-dev html-webpack-plugin
Copy the code

Then do the following in our configuration item webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
// ...
plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html'.template:  path.resolve(__dirname, './index.html')})]// ... 
Copy the code

Then change the HTML in the root directory to

<! DOCTYPEhtml>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
Copy the code

Then run the pack command NPM run build and pack successfully!! Of course, the HTML-webpack-plugin has many other capabilities, but we will not expand here, interested friends can go to see the corresponding github!!

extract-text-webpack-plugin

Careful friends will find that in our existing CSS (SCSS used here), there is no separate out, if you do not know which side of csS-loader related configuration comes from, you can go back to see the vue-loader that piece. In order to make our CSS independent, we use the extract-text-webpack-plugin.

First we install dependencies

npm install --save-dev extract-text-webpack-plugin
Copy the code

After installation we added and modified the following contents in webpack.config.js

const ExtractTextPlugin = require("extract-text-webpack-plugin");
// module.rules 
  {
    test: /\.scss$/,
    use: ExtractTextPlugin.extract({
      fallback: 'vue-style-loader'.use: [{loader: 'css-loader'.options: {
            esModule: false}},'sass-loader']})}// plugins.new ExtractTextPlugin('styles.css')...Copy the code

An error was reported after running the package command!The extract-text-webpack-plugin does not support webpack4. The extract-text-webpack-plugin does not support webpack4. Try installing the dependency below

npm install --save-dev extract-text-webpack-plugin@next
Copy the code

Repackage! Repackage! At this point we see that the folder we generated for packaging is already as follows

uglifyjs-webpack-plugin

When we open our main file, we find that JS is not fully compressed and still has an annotated state, so if we want to compress the code, we have to introduce plug-insuglifyjs-webpack-pluginOf course, we can also modify oursmode:'production'He will also enable some of the built-in plug-ins belowThen uglifyjs-Webpack-plugin is included, so our current requirements can also be met. If there are more customized requirements, we still need to pull the dependency by ourselves and configure it according to the configuration items

webpack-bundle-analyzer

Finally, the basic package content has been configured for 7788. The optimized content will be discussed in the optimization section later. Let’s configure the package volume analysis tool Webpack-Bundle-Analyzer

First we install depend on https://github.com/webpack-contrib/webpack-bundle-analyzer first and then introduce the following content in the code

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// plugins
[
	...
	new BundleAnalyzerPlugin()
	...
]
Copy the code

Run the command!npm run build

conclusion

Here is our webpack-Vue scaffolding build section to a paragraph, after the completion of a most basic most basic Vue scaffolding (build) is completed, if you want to configure more detailed, or more excellent scaffolding, please do not miss the back of the other related articles oh, station big big ladies have any questions, Please BB me directly, we learn from each other!!