带你由浅入深探索webpack4(一)
相信你或多或少也听说过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的版本

当输出版本号时,证明安装成功。(建议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:
src/js:
当然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

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

你或许会问npx是什么,我怎么从来没有用过,可能你一直都是在用npm run ** npx其实就是直接运行node_modules中的配置
当然你也可以在package.json中配置一下,像这样

配置之后你运用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="header.js"></script>
<script src="content.js"></script>
<script src="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,就会发现报了个错!

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

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

因为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后
 =>
=>
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 后
 =>
 =>
2.3 Mode配置
当我们每次打包的时候都会提示如下警告

这到底是什么呢? 其实就是叫我们设置工作状态,既mode
mode有两种状态,主要是用于表明当前开发状态!
development: 开发模式 打包后代码没有被压缩
production: 生产模式 打包后代码被压缩为一行

2.4 SourceMap配置
当我们的代码报错时,调试工具显示的是打包后js的报错行数,这样我们很难找到原代码到底在哪报错。
SourceMap主要用于开发模式下使用,其能展现出打包后文件与源文件的映射关系。
这到底是怎么用的呢? 查看下官方文档可以看到有这么多参数,不急,慢慢来解释:

+表示性能较好,-表示性能较差 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

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文件已经被成功引入.

加载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已经启动了一个服务器。

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!\n');
});
这时我们只需要在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。

这是因为我们每次更新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(一)的更多相关文章
- 带你由浅入深探索webpack4(二)
		在前一篇文章已经介绍了webpack4从入门到一些核心常用的用法,大家可以从上一篇文章看起.带你由浅入深探索webpack4(一) 接着上一章,接下来我们会继续探讨webpack4中的各种实用用法,让 ... 
- quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0
		quartz2.3.0系列目录 官网下载地址:http://www.quartz-scheduler.org/downloads/ 本系列demo全部来源于官网,仅仅是简化和汉化了注释!一部分代码de ... 
- Exploratory Testing 3.0 - 探索式测试
		最近看了James Bach新发的一篇文章,名为Exploratory Testing 3.0,文章链接:http://www.satisfice.com/blog/archives/1509 这篇文 ... 
- 硬盘网盘U盘全部可以丢掉了,这个设备可以让你享受随身带着几个T的感受
		前言 有小伙伴问我,你怎么老写技术类文章,能不能写点别的. 其实我兴趣挺广泛的,早年还有机会做个游戏博主,可惜最近2年金盆洗手了.戒了手游,ns和ps4都在吃灰.能完整玩完的游戏屈指可数.但是对于折腾 ... 
- 为什么说 Gradle 是 Android 进阶绕不去的坎 —— Gradle 系列(1)
		请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,欢迎 ... 
- 微信公众平台开发(二)——access_token、日志
		一.access_token 1)两种access_token,网页授权access_token和普通access_token 1.微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后, ... 
- 欢迎参加MVP主讲的Windows 10开发线上课程
		博客地址:http://blog.csdn.net/FoxDave Windows 10 Developer Readiness - Powered by MVPs - 由微软最有价值专家(MVP)主 ... 
- 这份书单,给那些想学Hadoop大数据、人工智能的人
		一.简单科普类 (文末附下载链接) 1.<人工智能:李开复谈AI如何重塑个人.商业与社会的未来图谱2> 作者:李开复,王咏刚 推荐理由:文章写得一般,但李开复和王永刚老师总结的还可以,算国 ... 
- (zhuan) 126 篇殿堂级深度学习论文分类整理 从入门到应用
		126 篇殿堂级深度学习论文分类整理 从入门到应用 | 干货 雷锋网 作者: 三川 2017-03-02 18:40:00 查看源网址 阅读数:66 如果你有非常大的决心从事深度学习,又不想在这一行打 ... 
随机推荐
- 20岁少年小伙利用Python_SVM预测股票趋势月入十万!
			在做数据预处理的时候,超额收益率是股票行业里的一个专有名词,指大于无风险投资的收益率,在我国无风险投资收益率即是银行定期存款. pycharm + anaconda3.6开发,涉及到的第三方库有p ... 
- Spring+Mybatis多数据源的一种实现方式,支持事务
			最近一个项目用到了多个数据库,所以需要实现动态切换数据源来查询数据,http://www.cnblogs.com/lzrabbit/p/3750803.html这篇文章让我受益匪浅,提供了一种自动切换 ... 
- MySQL中横表和竖表相互转换
			一 竖表转横表 1. 首先创建竖表 create table student ( id varchar(32) primary key, name varchar (50) not null, su ... 
- 第二章:第一个Netty程序
			第一步:设置开发环境 • 安装JDK,下载地址http://www.oracle.com/technetwork/java/javase/archive-139210.html • 下载netty ... 
- SSM-SpringMVC-12:SpringMVC中BeanNameViewResolver这种视图解析器
			------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 视图解析器,这个很熟悉啊,之间就用过,就是可以简写/和.jsp的InternalResourceViewRes ... 
- SSM-SpringMVC-09:SpringMVC中以继承MutiActionController类的方式实现处理器
			------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- MutiActionController类,多行动处理器,简单来说,就是可以一个处理器中有多个处理方法,分支 ... 
- Using variables inside Postman and Collection Runner
			Variables are among the most powerful features in Postman. Using variables in your Postman requests, ... 
- 你不知道的JavaScript--Item8 函数,方法,构造函数调用
			1.函数调用 Function绝对是JavaScript中的重中之重.在JavaScript中,Function承担了procedures, methods, constructors甚至是class ... 
- Python3 randrange() 函数
			描述 randrange() 方法返回指定递增基数集合中的一个随机数,基数缺省值为1. 语法 以下是 randrange() 方法的语法: import random random.randrange ... 
- IZT复杂电磁环境记录回放和模拟系统
			结合实验室复杂电磁环境特性与模拟研究需求,实现对复杂多变的电磁环境录制.分析.重构和模拟,记录回放系统应具备如下几项能力: 1.电磁环境信号记录能力:能够实现对9KHz-18GHz频带范围内射频信号的 ... 
