带你由浅入深探索webpack4(一)

摘要:
我相信你或多或少听说过webpack、gulf和其他前端构建工具。近年来,webpack变得越来越流行。可以说,它已经成为前端开发人员的必备工具。在过去的几天里,我重新整理了webpack中的知识点,并总结了一些常用知识点,希望能帮助您加深对webpack的理解。(因为我写这篇文章时,webpack的最新版本是4.3。如果某些配置有更改,请查看官方最新文档。然后我们直接在控制台上运行npxwebpack,然后返回项目。我们发现有一个额外的dist文件夹。本节将带您使用webpack。

 相信你或多或少也听说过webpack、gulp等这些前端构建工具。近年来webpack越来越火,可以说成为了前端开发者必备的工具。如果你有接触过vue或者react项目,我想你应该对它有所了解。

这几天我重新整理了一下webpack中知识点,把一些常用到的总结出来,希望能帮助到大家以及加深自己对webpack的理解。

(由于我在写这篇文章的时候webpack最新版本是4.3 如果某些配置有变更,请自行查看官方最新文档。千万别看中文文档,坑太多了更新太慢,很多属性都被弃用了,要看直接看英文的。)

一: 初识webpack

1.1 什么是webpack?

这个我直接引用官方文档的介绍:

Webpack 是当下最热门的前端资源模块化 管理和打包 工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分割,等到实际需要的时候再异步加载。

在这里我就不多介绍了,百度一搜一大堆介绍,本文章主要是介绍webpack怎么用。

1.2 安装webpack

因为webpack是基于nodejs实现的,所以要安装webpack,先得安装node

nodejs的中文网址:http://nodejs.cn/

下载完node之后,直接傻瓜式安装就好,接着,我们打开命令行,看下node和vue的版本

带你由浅入深探索webpack4(一)第1张

当输出版本号时,证明安装成功。(建议node尽量8.0版本以上 npm尽量6.0版本以上)。

这里我比较建议用淘宝的镜像cnpm,npm在国内实在是太慢了。

npm install -g cnpm --registry=https://registry.npm.taobao.org

当然,如果你网速快的话,用npm命令也没关系。

首先,我们创建一个空的文件夹,就起名叫webpack吧,然后执行一下初始化命令

npm init -y

接着安装webpack和webpack-cli(建议局部安装,全局安装webpack可能会导致webpack版本不同而无法正常使用)

npm install webpack webpack-cli --save-dev 或者 cnpm install webpack webpack-cli -save-dev

1.3 webpack的初始化配置

首先我们在本件的一级目录下创建一个src文件,src文件夹内再创建一个inde.js文件和一个index.html文件

src/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>初始化配置</title>
</head>
<body>
<div id="root">hello word!</div>
<script src="http://t.zoukankan.com/index.js"></script>
</body>
</html>
 

src/js:

var root = document.getElementById('root');
var text = document.createElement('div');
text.innerText = "斌果欢迎你!"
root.append(text);

当然packagej.json文件也要配置一下。

删除“main”入口配置添加"private"为true

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "private":true,
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.0"
  }
}

这样做主要是为了让你的项目私有化,防止意外发布你的代码。

接着,在一级目录下再创建一个 webpack.config.js  这个主要是webpack的配置文件

webpack.config.js

const path = require('path');

module.exports = {
    entry:'./src/index.js',  //打包文件的入口
    output:{                 //打包文件的出口
        filename:'bundle.js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

webpack使用的是common.js规范的语法,在webpack.config.js中设置了webpack打包的基本配置。

接着我们在控制台中直接运行

npx webpack

带你由浅入深探索webpack4(一)第2张

 再回到项目中的,发现多了一个dist文件夹。里面有一个打包后的bundle.js文件,就这样我们就将这个简单的项目打包成功了。

带你由浅入深探索webpack4(一)第3张

你或许会问npx是什么,我怎么从来没有用过,可能你一直都是在用npm run **  npx其实就是直接运行node_modules中的配置

当然你也可以在package.json中配置一下,像这样

带你由浅入深探索webpack4(一)第4张

配置之后你运用npm run bundle 效果其实和运行 npx webpack是一样,其最终还是运行npx webpack的命令.。

1.4 webpack的初次使用

在上一小节,你可能会觉得,这webpack打包完后好像也并没有用,到底webpack是用来干嘛的?这一小节,就带你用用webpak。

继续上一节,我们在src下继续创建header.js,connent.js、footer.js这三个文件.。

src/header.js

var root = document.getElementById('root');
var text = document.createElement('div');
text.innerText = "头部内容"
root.append(text);

src/content.js

var root = document.getElementById('root');
var text = document.createElement('div');
text.innerText = "中部内容"
root.append(text);

src/footer.js

var root = document.getElementById('root');
var text = document.createElement('div');
text.innerText = "尾部内容"
root.append(text);

如果我们想将这三个js同时引入到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>简单实例</title>
</head>
<body>
    <div id="root">hello word!</div>
    <script src="http://t.zoukankan.com/header.js"></script>
    <script src="http://t.zoukankan.com/content.js"></script> 
    <script src="http://t.zoukankan.com/footer.js"></script>
</body>
</html>

这样我们要引入3个js  对性能的消耗是十分巨大的 ,加入有100个这样的js文件,那我们不就要引入100个js?  于是我们想可以可以只引入一个inde.js。就像下面那样:

我们将src中引入的header、content、footer、index全部使用esModule语法如下

function header(){
    var root = document.getElementById('root');
    var text = document.createElement('div');
    text.innerText = "头部内容"
    root.append(text);
}
export default header;
import header from './header'
import content from './content'
import footer from './footer'

header();
content();
footer();

当我们打开html,就会发现报了个错!

带你由浅入深探索webpack4(一)第5张

这是为什么呢?  因为浏览器根本都不认识import是什么,是不认识es、common这些语言的,但是,webpack认识啊!

我们直接运行     npx webpack

带你由浅入深探索webpack4(一)第6张

然后我们index.html中直接引入打包后的bundle.js,就会神奇的发现他成功运行而且没报错。

带你由浅入深探索webpack4(一)第7张

因为webpack已经帮我们将esModule语法转化为浏览器能识别的法语告诉浏览器我要引入这三个js。

二、webpack的核心常用配置

2.1 HtmlWebpackPlugin

在上一章可以看到,当我们打包完成后,要自己将打包后的js代码引入到html文件中,这显得不那么智能。

HtmlWebpackPlugin插件做得工作就是在打包完成后,自动生成一个html文件,并将打包生成的js自动引入到html文件中。

首先安装这个插件:  npm install html-webpack-plugin -D

安装完成后,我们需要在webpack.config.js中配置一下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');  //++++导入插件

module.exports = {
    entry:'./src/index.js',  //打包文件的入口
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //++++其会根据该html文件作模板自动导入打包后的js ,然
        })                               //++++后将生成的html放到出口文件夹中
    ],                             
    output:{                 //打包文件的出口
        filename:'bundle.js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

这样的话就无需要我们自己配置html  其会在出口文件夹自动生成打包后的html。

运行npx webpack后

带你由浅入深探索webpack4(一)第8张=>带你由浅入深探索webpack4(一)第9张

2.2 CleanWebpackPlugin

当我们每次打包完文件后,都会生成一个新的dist文件覆盖上一个dist文件,但如果上个dist中有一些其他的文件没有被覆盖掉,就会成为杂鱼,当我们多次打包后,杂鱼可能就会变得越来越多,严重影响开发。

CleanWebpackPlugin插件做得就是每次打包时都会删除上一次打包的文件,而不是覆盖,这就使得每一次打包后的文件都是崭新的,而不会混合上一次遗留的文件。

首先安装这个插件: npm install clean-webpack-plugin -D

接着配置一下webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');  //++++导入插件

module.exports = {
    entry:'./src/index.js',  //打包文件的入口
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //其会根据该html文件作模板自动导入打包后的js ,然
        }),                             //后将生成的html放到出口文件夹中
        new CleanWebpackPlugin()    //++++配置删除的文件                              
    ],                             
    output:{                 //打包文件的出口
        filename:'bundle.js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

运行npx webpack 后

带你由浅入深探索webpack4(一)第10张 =>带你由浅入深探索webpack4(一)第11张

 2.3 Mode配置

当我们每次打包的时候都会提示如下警告 

带你由浅入深探索webpack4(一)第12张

这到底是什么呢? 其实就是叫我们设置工作状态,既mode

mode有两种状态,主要是用于表明当前开发状态!

development: 开发模式    打包后代码没有被压缩

production:    生产模式     打包后代码被压缩为一行

带你由浅入深探索webpack4(一)第13张

2.4 SourceMap配置

当我们的代码报错时,调试工具显示的是打包后js的报错行数,这样我们很难找到原代码到底在哪报错。

SourceMap主要用于开发模式下使用,其能展现出打包后文件与源文件的映射关系。

这到底是怎么用的呢? 查看下官方文档可以看到有这么多参数,不急,慢慢来解释:

 带你由浅入深探索webpack4(一)第14张

+表示性能较好,-表示性能较差  eval、inline、cheap、module等可以自由组合使用

none:不产生映射,速度最快。

eval:执行速度也很快,性能最好,当时代码提示不全面。

source-map:  把映射文件生成到独立的文件,一般不建议使用,打包速度过慢。

-inline-: 不单独生成文件,将生成的映射文件以base64的格式插入到打包后的js文件中,精确显示错误位置

-cheap-:代码只显示出错代码在第几行,不精确显示具体位置,有效提高打包效率。

-module-:不仅提示自己的业务代码是否出错,还提示第三方模块中的代码是否出错。

在开发环境中,建议使用:cheap-module-eval-source-map 

在生产环境中,上线代码一般不设置devtool。如果想知道报错位置,建议使用:cheap-module-source-map

因为我们主要在开发环境下,所以我们使用cheap-module-eval-source-map

带你由浅入深探索webpack4(一)第15张

 2.5资源管理配置

2.5.1 加载css、sass、css前缀

首先我们先在src下创建一个index.css

src/index.css:

body{
    background-color: blue;
}

接着我们在src中的index.js中导入css文件

src/index.js:

import header from './header'
import content from './content'
import footer from './footer'
import './index.css'    //+++引入css文件

header();
content();
footer();

由于webpack是无法识别以css后缀的文件,所以我们要引入loader(翻译官)帮我们解析css.

我们需要安装一下loader:  npm install style-loader css-loader --save-dev

安装完成后,我们还需要在webpack.config.js中配置一下:

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');  //导入插件

module.exports = {
    mode:'development',
    devtool:'cheap-module-eval-source-map',   //+++映射
    entry:'./src/index.js',  //打包文件的入口
    module:{
        rules:[
            {
                test:/.css$/,       //+++配置以css结尾的文件  
                use:[                //+++添加翻译官,顺序为由下向上,由右向左
                    'style-loader',
                    'css-loader'
                ]
            }          
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //其会根据该html文件作模板自动导入打包后的js ,然
        }),                             //后将生成的html放到出口文件夹中
        new CleanWebpackPlugin()    //配置删除的文件                              
    ],                             
    output:{                 //打包文件的出口
        filename:'bundle.js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

由于css翻译官解析后webpack还是不认识css文件,还需要使用style翻译官去处理一下才能被webpack所解析。

运行npx webpack打包后,我们直接打开dist下的index.html文件,就可以看到css文件已经被成功引入.

带你由浅入深探索webpack4(一)第16张

加载sass也是类似,只需要添加一个sass-loader、node-sass就可以了!在这里就不加演示。

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

而加前缀的话,在不同浏览器前缀各有不同。

  • Trident内核:主要代表为IE浏览器, 前缀为-ms
  • Gecko内核:主要代表为Firefox, 前缀为-moz
  • Presto内核:主要代表为Opera, 前缀为-o
  • Webkit内核:产要代表为Chrome和Safari, 前缀为-webkit

在这里我们只需要引入postcss-loader和autoprefixer就可以了

安装一下 : npm install postcss-loader autoprefixer --save-dev

在根目录下创建一个postcss.config.js文件

postcss.config.js:

module.exports = {
    plugins:[
        require('autoprefixer')
    ]
}

接着在webpack.config.js修改一下loader

           {
                test:/.css$/,       //配置以css结尾的文件  
                use:[                //添加翻译官,顺序为由下向上,由右向左
                    'style-loader',
                    'css-loader',
                    'postcss-loader'       //+++配置前缀
                ]
            },
            {
                test:/.scss$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'sass-loader',   //配置sass翻译官
                    'postcss-loader'   //+++配置前缀
                ]
            }      

但是如果我们要在sass中再引入sass 这就会出错,因为再引入的sass文件没有经过翻译官翻译.

所以,我们还需要配置一下sass

           {
                test:/.scss$/,
                use:[
                    'style-loader',
                    {
                        loader:'css-loader',
                        options:{
                            importLoader:2,//+++如果sass文件还引入其他sass,另一个会重新从下向上开始解析
                            modules:true //+++开启css模块打包
                        }
                    },
                    'sass-loader',          //配置sass翻译官
                    'postcss-loader'        //配置前缀
                ]
            }   

2.5.2 加载图片、字体

加载图片主要使用两个loader分别为 file-loader  url-loader

其两个loader都是解析图片。不过url-loader可以将小图片转化成base64的格式存放到打包后的css中

我们一般都是使用url-loader 这样处理小图片的时候就可以更快加载而无需引用原图片地址。

安装: npm install url-loader file-loader -D

配置:

webpack.config.js:

          {
                test:/.(png|jpg|gif|svg)$/,
                use:[
                    {
                        loader:'url-loader',
                        options:{
                            name:'[name].[ext]',
                            outputPath:'images/',
                            limit:8096  //+++小于4K的图片转化为base64存放到打包后的js中
                        }
                    }
                ]

            }        

因为file-loader和url-loader可以加载任何文件,所以我们也可以用其来加载字体文件

webpack.config.js:

           {
                test:/.(woff|woff2|eot|ttf|otf)&/,
                use:[
                    'file-loader'
                ]

            }

 2.5.3加载es6语法

由于很多低版本的浏览器都不支持ES6语法,所以,我们需要将ES6语言转换为ES5的语法。

在以前我都是用babel-preset-es2015转换的,现在官方推荐使用babel-preset-env转换,我们就使用官方推荐的来转换吧.

由于babel只转换语法,需要使用babel-polyfill来支持新语法像promise这些。

首先我们先安装依赖  npm install babel-loader @babel/core babel-preset-env @babel/polyfill -D

接着我们在webpack.config.js中配置一下

webpack.config.js:

{
                test: /.js$/,
                exclude: /node_modules/,//不需要对第三方模块进行转换,耗费性能
                use:[
                    'babel-loader'
                ] 
       

            },

因为bebel配置的信息太多了,我们可以在根目录下创建一个.babelrc文件

.babelrc:

{
    "presets": [
        [
            "babel-preset-env", {         
                "targets": {         //在这些版本以上的浏览器中不转换为es5
                    "chrome": "67",
                    "firfox":"60",
                    "edge":"17",
                    "safari":"11.1"
                },
                "useBuiltIns": "usage"
            }
        ]
    ]
}

最后我们还需要在index.js中引入polyfill:

src/index.js:

import "@babel/polyfill";

但是如果在第三方模块时使用@babel/polyfill会污染全局变量,所以我们可以使用runtime-transform插件

其与polifill类似,但不会污染全局变量其用法和上面差不多

我们安装一下:

npm install babel-runtime babel-plugin-transform-runtime -D

在.babelrc中添加配置就可以了。

{
    "plugins": ["transform-runtime"]
}

更多的配置可以参考官网文档:babeljs.io/setup

2.6配置多个出入口文件

在目前,我们一直以一个index.js为入口,bundle.js文件为出口,但随着程序的增加,我们可能需要输出多个bundle文件。

这个很简单,我们新建一个print.js文件,并添加一些逻辑

import Header from './header'

Header();
console.log('这是打包的第二入口文件');

然后我们只需要修改一下webpack.config.js中的出入口配置就可以了。

webpack.config.js:

 entry:{
        main:'./src/index.js',       //打包入口文件
        print:'./src/print.js'
    },
......
 output:{
       filename:'[name].js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
     }

2.7热更新配置

我们每次打包的时候,都需要手动运行npm run bundle 或者npx webpack这显得什么繁琐。

下面介绍几个配置,可以在代码发生变化后自动编译代码。

2.7.1观察模式watch

我们只需要在package.json文件中添加一个用于启动观察模式的npm script脚本就可以了;

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "bundle": "webpack",
    "watch": "webpack --watch"    //+++添加启动脚本
  },
   "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.5.1",
    "clean-webpack-plugin": "^2.0.1",
    "css-loader": "^2.1.1",
    "file-loader": "^3.0.1",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.11.0",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.0"
  }
}

这样当我们修改js中的代码时,其会自动执行打包,我们只需要刷新一下页面就可以看到变化。

2.7.2使用webpack-dev-server

当我们使用watch时,我们虽然可以自动打包,但是页面不能自动刷新,需要我们手动刷新。

webpack-dev-server为我们提供了一个简单的web服务器,能够实时重新加载。

我们首先需要安装一下: npm install webpack-dev-server -D

接着我们需要修改webpack.config.js配置,告诉服务器,在哪里查找文件。

webpack.config.js:

......

module.exports = {
    mode:'development',
    devtool:'cheap-module-eval-source-map',   //映射
    entry:{                     //配置入口文件
        main:'./src/index.js',
        print:'./src/print.js'
    },
    devServer:{
        contentBase:'./dist',      //+++配置运行目录
        open:true,                 //+++自动打开浏览器
        port:8080,                 //+++服务器访问端口
        proxy:{                    //+++配置跨越代理
            'api':'http://loacalhost:3000'
        }
    },
   ......
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //其会根据该html文件作模板自动导入打包后的js ,然
        }),                             //后将生成的html放到出口文件夹中
        new CleanWebpackPlugin()    //配置删除的文件                              
    ],                             
    output:{                 //打包文件的出口
        filename:'[name].js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

然后我们只需要在package.json中添加一个script脚本用于启动即可,

 "scripts": {
    "bundle": "webpack",
    "watch": "webpack --watch",
    "server": "webpack-dev-server"    //+++启动wepack-dev-server
  },

运行npm webpack server 就可以看到webpack已经启动了一个服务器。

带你由浅入深探索webpack4(一)第17张

2.7.3使用webpack-dev-middleware

webpack-dev-middleware是一个容器,它可以吧webpack处理后的文件传递给一个服务器。webpack-dev-server在内部就是使用了它。

这个仅仅了解就可以了,没必要自己写一个server,且性能没有webpack-dev-server好。这里主要是配合express server来使用

首先我们自己安装一下:npm install express webpack-dev-middleware --save-dev

然后我们需要在webpack.config.js中配置一下

output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist'),
      publicPath: '/'      //+++
    }

接着我们需要创建一个server.js

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
  publicPath: config.output.publicPath
}));

// Serve the files on port 3000.
app.listen(3000, function () {
  console.log('Example app listening on port 3000!
');
});

这时我们只需要在package.json中添加一个srcipt脚本然后直接运行脚本就可以了

"server": "node server.js",

2.8模块热替换(HMR)

当我们启动server时,如果修改某个模块,它就会整个网页重新刷新,之前的操作又得重来。

HMR就是允许运行时更新各种模块,而不用完全刷新。也就是只更新有变动的模块,其他模板不动。

注:HMR只适合在开发环境下,并不适合在线上环境下配置。

因为HMR是webpack内置的插件,所以无需再下载,在使用之前,我们先将print.js删除。再引入HMR的相关配置。

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');  //导入插件
const webpack = require('webpack');     //+++导入webpack

module.exports = {
    mode:'development',
    devtool:'cheap-module-eval-source-map',   //映射
    entry:{                     //配置入口文件
        main:'./src/index.js'
    },
    devServer:{
        contentBase:'./dist',      //配置运行目录
        open:true,                 //自动打开浏览器
        port:8080,                 //服务器访问端口
        proxy:{                    //配置跨越代理
            'api':'http://loacalhost:3000'
        },
        hot:true,              //+++开启热更新
        hotOnly:true            //+++即使html错误,也不让页面更新,           
    },
    ......
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //其会根据该html文件作模板自动导入打包后的js ,然
        }),                             //后将生成的html放到出口文件夹中
        new CleanWebpackPlugin(),    //配置删除的文件    
        new webpack.NamedModulesPlugin(),        //+++以便更容易查看要修补(patch)的依赖
        new webpack.HotModuleReplacementPlugin()      //+++使用模块热替换插件
    ],                             
    output:{                 //打包文件的出口
        filename:'[name].js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

到这里还没有完  要想实现热替换,还要配置一下index.js

import header from './header'
import content from './content'
import footer from './footer'
import './index.css'    //引入css文件

header();
content();
footer();

//如果模块启用了HMR,就可以用 module.hot.accept(),监听模块的更新。
if (module.hot) {
    module.hot.accept('./header.js', function() {
       header()
    })
  }
  

当我们单修改header.js时,其他模块并不会影响,只会更新header模块的内容。但我们会发现修改header会创建一个新的dom。

带你由浅入深探索webpack4(一)第18张

这是因为我们每次更新header模块都创建了一个dom 我们需要先修改一下js代码在更新前先清除之前添加的dom节点。

所以在使用HMR时要根据不同的代码做相应的设置。

HMR修改样式表

这个就更简单了,其实在上面我们应该实现了这个功能,无须做任何修改,当我们修改css样式时,其他模块是不会刷新的。无需设置module.hot.accept。

因为style-loader已经帮我们在后台使用 module.hot.accept 来修补(patch) <style> 标签。

2.9 tree shaking

在我们编写代码时或引入第三方库的时候,很多时候会引入很多冗余的代码,不经意间增大了性能的消耗。

tree shaking是一个术语,通常用于描述移除JavaScript上下问中未引用的代码,其只支持es6模块例如import和export。

实现这个功能很简单,只需要在package.json中配置“sideEffects”属性就能实现。

"sideEffects":["*.css"],   //+++对所有css不使用Tree shaking。

如果将其设置为false则对所有使用tree shaking。如果不想怕误删的文件可以写在数组里。

在生产环境中,其会自动压缩打包,无需设置optimization,如果在开发环境中还是要配置一下的。

webpack.config.js:

......
module.exports = {
    mode:'development',
    devtool:'cheap-module-eval-source-map',   //映射
    entry:{                     //配置入口文件
        main:'./src/index.js'
    },
......
    optimization:{          //+++在开发环境中配置,生产环境不用
        usedExports:true
    },                          
    output:{                 //打包文件的出口
        filename:'[name].js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

2.10生产环境构建

在我们之前的开发中一直都是以开发环境开发为主,然而生产环境与开发环境有很大的区别,在开发环境中,注重的是怎样使开发更便利,而在生产环境中注重的是如果使代码性能更高,简而精。所以我们很有必要将开发环境和生产环境分离出来。

在这里我们应该抽取出他们的公共部分,再将它们与公共配置分别合并在一起,这时,我们就需要一个工具:webpack-merge

首先,我们先安装一下这个工具。

npm isntall webpack-merge -D

然后我们需要创建三个文件:webpack.common.js、webpack.dev.js、webpack.prod.js。我们将公共部分抽离到webpack.common.js中,删除掉webpack.config.js

 webpack.common.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');  //导入插件
const webpack = require('webpack');     //导入webpack

module.exports = {
   
    entry:{                     //配置入口文件
        main:'./src/index.js'
    },
   
    module:{
        rules:[
            {
                test: /.js$/,
                exclude: /node_modules/,//不需要对第三方模块进行转换,耗费性能
                use:[
                    'babel-loader'
                ]
            },
            {
                test:/.css$/,       //配置以css结尾的文件  
                use:[                //添加翻译官,顺序为由下向上,由右向左
                    'style-loader',
                    'css-loader',
                    'postcss-loader'    //配置前缀
                ]
            },
            {
                test:/.scss$/,
                use:[
                    'style-loader',
                    {
                        loader:'css-loader',
                        options:{
                            importLoader:2,//如果sass文件还引入其他sass,另一个会重新从下向上解析
                            modules:true //开启css模块打包
                        }
                    },
                    'sass-loader',          //配置sass翻译官
                    'postcss-loader'        //配置前缀
                ]
            },
            {
                test:/.(png|jpg|gif|svg)$/,
                use:[
                    {
                        loader:'url-loader',
                        options:{
                            name:'[name].[ext]',
                            outputPath:'images/',
                            limit:8096  //小于4K的图片转化为base64存放到打包后的js中
                        }
                    }
                ]
            },
            {
                test:/.(woff|woff2|eot|ttf|otf)&/,
                use:[
                    'file-loader'
                ]
            }        
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'   //其会根据该html文件作模板自动导入打包后的js ,然
        }),                             //后将生成的html放到出口文件夹中
        new CleanWebpackPlugin()   //配置删除的文件    
    ],              
    output:{                 //打包文件的出口
        filename:'[name].js',          //打包后的文件名
        path:path.resolve(__dirname,'dist')      //打包后文件存放的位置
    }
}

webpack.dev.js:

const webpack = require('webpack');     //导入webpack
const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common,{
    mode:'development',
    devtool:'cheap-module-eval-source-map',
    devServer:{
        contentBase:'./dist',    //配置运行目录
        open:true,               //自动打开浏览器
        port:8080,               //服务器访问端口
        hot:true                 //开启热更新
    },
    plugins:[
        new webpack.NamedModulesPlugin(),         //以便更容易查看要修补(patch)的依赖
        new webpack.HotModuleReplacementPlugin()   //使用模块热替换插件
    ],
    optimization:{        //在开发环境中配置,生产环境不用
        usedExports:true
    }
})

webpack.prod.js:

const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common,{
    mode:'production',
    devtool:'cheap-module-source-map'
})

 接着我们只需在package.json中配置一下script脚本,运行不同的脚本进行不同环境下的打包

package.json:

 "dev":"webpack-dev-server --config ./webpack.dev.js",   
"build":"webpack --config ./webpack.prod.js"

免责声明:文章转载自《带你由浅入深探索webpack4(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IntelliJ IDEA 无法热加载自动更新,On 'update' action:选项里面没有update classes and resources这项canvas基础路径(2)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

用js实现图片的无缝滚动效果

实现图片的无缝滚动就是要让你的图片集在一定时间里自动切换,那就需要js里的定时器来控制时间。   js中关于定时器的方法有两种:setTimeout和setInterval。它们接收的参数是一样的,第一个参数是函数,用于定时器的执行,第二个参数是数字,表示多少毫秒之后执行函数。它们的不同点在于setTimeout只执行一次指定的函数,而setInterva...

webpack安装&amp;amp;指定版本安装&amp;amp;遇到的问题

1.安装nodejs,安装完成,cmd命令行中输入node -v 查看版本号,版本号显示则说明安装成功2.npm包管理器是集成在node中的,输入 npm -v,显示npm版本号3.创建package.json文件,输入命令 npm init,工程目录下就会生成一个package.json文件(全局安装webpack) 4.安装webpack,输入命令 n...

css解决ios滑动不流畅

-webkit-overflow-scrolling:touch -webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效果.auto: 使用普通滚动, 当手指从触摸屏上移开,滚动会立即停止。touch: 使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果。继续滚动的速度和持续的时间和滚...

前端开发要注意的浏览器兼容性问题整理

首先,我们要知道,为什么各浏览器会产生兼容性问题?     产生这个问题的主要原因是市面上的浏览器的种类很多,但由于不同的浏览器的内核不一致,从而导致各个浏览器对网页的解析就产生了差异。解决浏览器兼容性问题,还是从三个方面入手:html部分、css部分、js部分。       1、html部分       a、最突出也是最容易想到的就是高版本的浏览器用了低...

customize-cra 打包时 去除 map 文件

config-overrides.js const { override, fixBabelImports, addLessLoader, addWebpackAlias } = require('customize-cra'); const path = require('path'); function resolve(dir) {...

Node.js躬行记(4)——自建前端监控系统

这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2。将性能和错误量化。因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统。其实在很早以前就有这个想法,当时已经实现了前端的参数搜集,只是后台迟迟没有动手,也就拖着。 目前完成的还只是个雏形,仅仅是搜集了错误和相关的性能参数。 后台样式采用了封装过的matrix。 分析功能还很薄弱...