preface

In the last phase, I built a basic version of VUe-CLI project from scratch, mainly introducing the installation of Loader and the usage of some configuration items, and adding less preprocessor to the project

Links from the previous issue – from building VUE – scaffolding to mastering webpack configuration (one. Basic configuration)

This installment begins with the introduction of common plug-ins to implement some of the functions that development and build environments use, such as hot plugging, CSS style extraction, common module extraction, extraction code compression, and more

Note that this tutorial applies to webpack3 and does not support webpack4 or later

Distinguish between development and production environments

Many plug-in features are used in development but not in production, and vice versa. Such as

– use of development
  • Hot swap debugging
  • Generating HTML templates
– use of production
  • Generating HTML templates
  • CSS style extraction
  • Common module extraction
  • JavaScript compression
  • .

To quote the official line, there are two ways to distinguish between production and development environments, as shown below

The second approach involves a secondary wrapper, like the official VUe-CLI build project, divided into three configuration files, which is a bit more complicated for us at the moment, so we used the first approach, setting environment variables to differentiate the deployment environment.

Referring to the VuE-CLI-generated webpack-Simple project, we found that NPM script was written a little strangely

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

Develpoment = production and cross-env NODE_ENV= developer and production. That’s how we assigned the environment variable to develpoment

npm install --save cross-env
Copy the code

The process.env object also provides configuration information from package.json, which involves node knowledge.

// Get the project version number const version = process.env.npm_package_versionCopy the code

To keep things simple, put the determination of environment variables directly at the bottom of the webpack.config.js file

const path = require('path')
const webpack = require('webpack')

module.exports = {
    entry:{
        app:'./src/main.js'} / /... } /** ** is triggered only when production code is generatedif (process.env.NODE_ENV === 'production') {
    // http://vue-loader.vuejs.org/en/workflow/production.html
    module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
            'process.env': {
            NODE_ENV: '"production"'}}}),])Copy the code

If there are more and more additional configuration items in the future, it is not a good idea to merge the configuration items as described above. In the end, you still need to pull out another JS file to load the new or overwritten configuration items and merge the configuration objects using the Webpack-Merge middleware.

The webpack.defineplugin plugin is a plugin for setting global constants, remember! Remember to write ‘production’ when assigning, that’s what the DefinePlugin says

Note that because this plug-in performs text substitution directly, the given value must contain the actual quotes inside the string itself. In general, there are two ways to achieve this effect, using ‘ ‘production’ ‘, or using json.stringify (‘production’).

Generating HTML templates

Before, the index. HTML root directory required us to introduce the JS resource address by ourselves, and any new resources had to be introduced manually, which was very troublesome. At this time, HtmlWebpackPlugin was used to generate HTML files with all resources in the dist directory according to index. HTML as a template.

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

Add plugins to the output object. The data value is an array, and the array member new [plugins]() adds the plugins. Each plug-in has its own configuration items and specifications, which can be found in NPMJS or their official documentation

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')

module.exports = {
    entry:{
        app:'./src/main.js'
    },
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:"js/[name].js", }, module:{ rules:[ //... ]  }, plugins:[ new HtmlWebpackPlugin({ filename:'index.html',
            title:'vue demo',
            template:'./index.html',
        })
    ],
    externals:{
        'jquery':'window.jQuery'}}Copy the code
instructions
  • filenameThe file name of the generated HTML file, if left blank, defaults to the original file name
  • titleThe content of the title tag
  • templateHTML template address, here we use the index. HTML directory I built in the previous issue

Here is a detailed explanation of the HtmlWebpackPlugin

The contents of index.html need to be changed, because webpack automatically adds resource addresses to the HTML file, so we need to delete the original script tags

<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue demo</title>
</head>
<body>
    <div id="app">
     
    </div>
    <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script>
</body>
</html>
Copy the code

Some people may wonder why jQuery for CDN is added here, because I will mention a point here: sometimes we can use CDN accelerated library resources, but do not know how to use in the project.

It’s very simple. We import it directly in the HTML template and then add externals to the webpack.config.js configuration.

// webpack.config.js
externals:{
    'jquery':'window.jQuery'} // import $from from app.vue'jquery'
Copy the code

Hot replacement

The web server

Install webpack-dev-server before using hot replace

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

Webpack-dev-server is actually a separate plug-in, but WebPack has its configuration items built in, and the attribute devServer corresponds to its configuration items.

module.exports = {
    entry:{
        app:'./src/main.js'
    },
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:"js/[name].js",
    },
    devServer:{
        contentBase:"./dist"}}Copy the code

The default port address is http://localhost:8080/, which is set to contentBase with the resource directory address. For more details on the configuration, see the official documentation dev-server. I haven’t really read it. Hee hee.

Hot replacement plug

Hot replacement is the modification of the file content during the development process does not need to refresh the page frequently, the modification will be automatically synchronized to the browser, Webpack already has this plug-in, do not need to install directly to use it. In the plugins to add a new webpack. HotModuleReplacementPlugin () with respect to ok

plugins:[
        new HtmlWebpackPlugin({
            filename:'index.html',
            title:'vue demo',
            template:'./index.html',
        }),
        new webpack.HotModuleReplacementPlugin()
    ]
Copy the code

Change NPM scripts

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

Run NPM run dev and the hot deployment is complete

These are the plugins for the development environment, and here are the plugins for the build environment

CSS file and vUE inside style extraction

If CSS styles are not extracted, all styles in.CSS files and vue will be added to the page head in the form of style tags, which will hinder the cache of resources and slow down the page load speed.

Use the extract-text-webpack-plugin to install it as usual

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

Use this plug-in to filter the CSS loader before using it

var ExtractTextPlugin = require("extract-text-webpack-plugin")

module.exports = {
  // other options...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            css: ExtractTextPlugin.extract({
              use: 'css-loader',
              fallback: 'vue-style-loader'// <- this is a dependency of vue-loader}), // use less or sass'less': ExtractTextPlugin.extract({
                use:[
                    'css-loader'.'less-loader'
                ],
                fallback:'vue-style-loader'
            })
          }
        }
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("styles/style.css")]}Copy the code

Vue style should be extracted from fallback, so add the loader’ vue-style-loader’ to fallback. If you run the error, then manually install it.

Generate multiple files

My general habit is to the external introduction of CSS files that can be reused, and vue style is not the same for each page to be generated, so I built two instances of ExtractTextPlugin respectively extract styles into two files.

const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const ExtractRootCss = new ExtractTextPlugin({filename:'styles/root.css',allChunks:false});
const ExtractVueCss = new ExtractTextPlugin({filename:'styles/[name]/style.css',allChunks:true});

module.exports = {
    //other options...
    module:{
        rules:[
        //...
            {
                test: / \. CSS $/, / / here with ExtractRootCss use: ExtractRootCss. Extract ({fallback:'style-loader',
                    use:['css-loader']})}, {test: / \. Less $/, / / here with ExtractRootCss use: ExtractRootCss. Extract ({fallback:'style-loader',
                    use:[
                        'css-loader'.'less-loader']})}, {test:/\.vue$/,
                loader:'vue-loader', options:{loaders:{// ExtractVueCss used here'css': ExtractVueCss.extract({
                            use: 'css-loader',
                            fallback: 'vue-style-loader'// <- This is a vue-loader dependency, so if nPM3 is used, no explicit installation is required}), // ExtractVueCss is used here'less':
                        ExtractVueCss.extract({
                            use:[
                                'css-loader'.'less-loader'
                            ],
                            fallback:'vue-style-loader'
                        })
                    },
                }
            },
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            filename:'index.html',
            title:'vue demo',
            template:'./index.html',}), ExtractRootCss, / / fill in the plugin instance, the reuse of CSS ExtractVueCss, / / remember to fill in according to the order in the vue CSS new webpack. HotModuleReplacementPlugin (),]}Copy the code

This is how the ExtractTextPlugin plugin generates multiple files. You can also configure it as you like.

Common code extraction

In multi-page or multi-entry scenarios (with more than one entry), different modules (chunks) will introduce the same resource modules (i.e., js files introduced by import) many times, as well as vUE and other library codes. It is better to separate these reused codes to facilitate caching. Reduce the size of the package on the one hand.

The CommonsChunkPlugin is the solution to this problem, and it’s a dependency on the Webpack.optimize object so it doesn’t have to be installed. Specific use is as follows

new webpack.optimize.CommonsChunkPlugin({
    name: 'vender',
    minChunks:2
})
Copy the code

The minChunks parameter can be of type “number”, with “2” indicating that there are more than two chunks used in common chunks that will be packed into vender.js. MinChunks can also pass a method that returns a Boolean value.

(Chunk can simply be understood as the whole relationship tree generated by the entry attribute setting. So far, the project has only one chunk, namely ‘app’. Of course, the vender generated by the plug-in is also a chunk. For beginners, this is the way to understand, with more natural concepts)

Since there is only one chunk, let’s first extract code from a common library, such as the vue package. Put the code in the production environment

/* Only when production code is generated */if (process.env.NODE_ENV === 'production') {
    module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
            'process.env': {
            NODE_ENV: '"production"'}}), / / extraction from node_modules into modules, such as the vue new webpack.optimize.Com monsChunkPlugin ({name:'vender',
            minChunks:function(module,count){ var sPath = module.resource; // console.log(sPath,count); // Matches the node_modules file directoryreturn sPath &&
                    /\.js$/.test(sPath) &&
                    sPath.indexOf(
                        path.join(__dirname, 'node_modules') === 0}})])}Copy the code

This is the introduction of commons-chunk-plugin in the Chinese document

This is a good Samaritan to summarize the results of the various configuration cases packaged segmentfault.com/a/119000000…

Other plug-ins

Source mapping

Since refactoring and compressed code is not good for debugging, we first need to enable source Map and add a Devtool to the Webpack configuration, as shown below

module.exports = {
    //entry: ...
    devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
    module.exports.devtool = '#source-map'
}
Copy the code

Eval-source-map is the source map for the development environment, and source-map is the source map for the build environment

The official introduction to Devtool is here

Ruan Yifeng’s introduction to Source Map is here

Js code compression

UglifyJs. Webpack contains UglifyJsPlugin plugins. Plugins can be used to compress CSS files.

new webpack.optimize.UglifyJsPlugin({
    sourceMap: true// enable source mapping. Compress: {warnings:false// go to warning}}),Copy the code

But the above usage is a legacy of webpack1.0, using an older version of UglifyJs, and its instructions are also in the wepack1.0 documentation. You can manually install uglifyJS -webpack-plugin to introduce the latest UglifyJS

/* npm install -save-dev uglifyjs-webpack-plugin */

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

new UglifyJsPlugin({
  uglifyOptions: {
    compress: {
      warnings: false}},sourceMap: true
})
Copy the code

The webpack3.0 Chinese documentation explains the plug-in here

An introduction to the official documentation is here

Webpack1.0 migration plug-in

Loader-options-plugin is different from other plug-ins. Its purpose is to help people migrate from WebPack 1 to WebPack 2. The official instructions

new webpack.LoaderOptionsPlugin({
    minimize: true
}),
Copy the code

Run the build and try it out

Well, most of the plugins you’ve used so far have been introduced into the WebPack configuration, so let’s try it out.

The full webpack.config.js code is here at pan.baidu.com/s/1jKnDSYa

npm run dev
Copy the code

npm run build
Copy the code

The uglifyJs error was found because we did not configure Babel’s translator and compiler rules. The configuration instructions for Babel will be in the next issue due to limited space.

Solution: create a file in the root directory. Babelrc

{
  "presets": [["env", {
       "modules": false}}]]Copy the code

Install babel-preset-env, NPM install –save-dev babel-preset-env

Then build, no problem

The directory structure is as follows

Nagging a few words

To learn more about the specific use of each plug-in, make sure to consult more documentation and resources to customize your requirements. For your convenience, I have given a large number of links below each plug-in in the tutorial, which can be said to save you baidu time, suddenly feel very careful.

Official documents do not need to see all, use what to see what, what function configuration to focus on that part is good, wait for time to briefly go over the document.

Next up

So far, the whole project can be said to be fully usable. Vue init Webpack-simple project-name (vue init webpack-simple project-name)

Unfortunately, there is still no mention of postCSS and Babel configuration, which will be covered briefly in the next installment, and then we will continue to optimize the build process to accommodate multi-entry, multi-page development. Want to understand the future content can pay attention to oh ~~

Issue 3 has been updated: from Building VUe-scaffolding to mastering webpack configuration (iii). Multi-page build)

reference

  • Webpack multi-page/entry support & common components packaged separately

  • How does Webpack integrate third-party JS libraries

  • www.css88.com/doc/webpack…

  • Segmentfault.com/a/119000000…

  • Segmentfault.com/a/119000000…