版本号
以entry.js打包为bundle.js为例,出口的filename可以设置为[id]、[name]、[hash]、[chunkhash]等替换形式,如下所示
var webpack = require('webpack'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: '[id]-[name]-[hash].js'//出口名称 } }
则出口文件为0-main-0c1dce21f6c5db455fb4.js
如果index.html要引用打包后的js文件,由于文件名称不确定,并不好解决。这时,就需要使用html-webpack-plugin插件。该插件并不是内置插件,所以需要安装
npm install html-webpack-plugin
HtmlWebpackPlugin简化了HTML文件的创建,以便为webpack包提供服务。这对于在文件名中包含每次会随着变异会发生变化的哈希的webpack bundle尤其有用
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: '[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ title: 'match',//生成的html文件的标题为'match' filename: 'index.html'//生成的html文件名称为'index.html' }) ] }
通过以上的配置,如果在当前路径,index.html不存在,则生成;如果存在,则替换
[注意]如果htmlwebpackplugin不进行配置,参数为空, plugins: [new HtmlWebpackPlugin()]。默认地,生成的html文件名称为'index.html',标题为'Webpack APP'
【标签位置】
htmlwebpackplugin插件的常用设置是设置script标签插入的位置,默认插入到body标签中,但可以使用inject:'head',设置插入到head标签中
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ inject:'head',//将script标签插入到head标签中 filename: 'index-[hash].html',//生成的html文件名称为'index.html' }) ] }
【图标设置】
设置favicon属性,可以设置网页的小图标
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ favicon:'./icon.ico' }) ] }
【压缩】
设置minify属性,可以压缩html文件,默认为false,即不压缩
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './entry.js', //入口文件
output: {
path: __dirname,//出口路径
filename: 'js/[id]-[name]-[hash].js'//出口名称
},
plugins: [
new HtmlWebpackPlugin({
minify:{// 压缩html
removeComments: true,//删除注释
collapseWhitespace:true//删除空格
}
})
]
}
使用webpack打包后的index.html代码如下
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Webpack App</title></head><body><script type="text/javascript" src="js/0-main-8128c0c26a4449da7a05.js"></script></body></html>
模板文件
HtmlWebpackPlugin除了提供模块版本号的功能,还可以使用模板文件
例如,模板文件为template.html,内容如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>template</title> </head> <body> <script src="test.js"></script> <div>test</div> </body> </html>
webpack配置文件如下
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ filename: 'index-[hash].html',//生成的html文件名称为'index.html' template:'template/template.html'//模板文件为'template.html' }) ] }
生成的index-[hash].html以'template.html'文件为模板
[注意]如果在htmlwebpackplugin中使用了模板,则指定title不会生效,因为要以模板的title为准
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ title:'test', filename: 'index-[hash].html',//生成的html文件名称为'index.html' template:'template/template.html'//模板文件为'template.html' }) ] }
【传参】
模块文件当然是可以传参的,一般地,使用ejs语法。例如,在模板文件中,使用<%= htmlWebpackPlugin.options.title %>,即可读取htmlWebpackPlugin插件中'title'属性的值
[注意]模板文件中的'htmlWebpackPlugin'是固定的,不能随意更改。与webpack.config.js文件中,require()该插件的命名无关
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ title:'test', template:'template/template.html',//模板文件为'template.html' dateData: new Date() }) ] } //template.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <div><%=htmlWebpackPlugin.options.dateData %></div> </body> </html>
【模板组件】
下面利用模板组件组合成一个html文件,以ejs模板语言为例
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ template:'template/template.html'}) ] } //template.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div> <% include template/header.html %> </div> <ul> <% var arr = [1,2,3,4,5] %> <% for(var i = 0; i < arr.length; i++){ %> <li><%=arr[i] %></li> <% } %> </ul> <div> <% include template/footer.html %> </div> </body> </html> //header.html <div>我是头部</div> //footer.html <div>我是尾部</div>
运行结果报错,提示子模板加载失败
这是因为HtmlWebpackPlugin插件并不具备ejs模板语言所有的功能,其中一个就是不能识别<%include %>语句,这时需要安装一个ejs-compiled-loader
npm install ejs-compiled-loader
安装完成后,修改配置文件如下,表示使用ejs-compiled-loader来编译template.html
[注意]该插件中的include路径相对于webpack配置文件的位置,而不是模板文件template.html的位置
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ template:'ejs-compiled-loader!template/template.html'}) ] }
结果如下
多页面
对于多页面来说,一般地,有多个入口文件。不同的html页面输出对应不同的入口文件。 插件plugins()是一个数组,每new一个HtmlWebpackPlugin(),就可以输出一个html页面。这里有两个重要的属性:chunks和excludeChunks,chunks表示所包含的入口文件,excludeChunks表示要排除的入口文件
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { a:'./src/js/a.js', b:'./src/js/b.js', c:'./src/js/c.js' }, output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ filename:'a.html', template:'src/template/template.html', title:'this is a', chunks:['a'] }), new HtmlWebpackPlugin({ filename:'b.html', template:'src/template/template.html', title:'this is b', chunks:['b'] }), new HtmlWebpackPlugin({ filename:'c.html', template:'src/template/template.html', title:'this is c', excludeChunks:['a','b'] }), ] }
结果如下
//a.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this is a</title> </head> <body> <div></div> <script type="text/javascript" src="js/2-a-9828ea84bd8c12c19b5f.js"></script></body> </html> //b.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this is b</title> </head> <body> <div></div> <script type="text/javascript" src="js/1-b-9828ea84bd8c12c19b5f.js"></script></body> </html> //c.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this is c</title> </head> <body> <div></div> <script type="text/javascript" src="js/0-c-9828ea84bd8c12c19b5f.js"></script></body> </html>
内联
在前面的例子中,都是以链接的形式引入入口文件的。有时,为了追求性能,会将其处理为内联的形式。这里就需要安装一个扩展插件html-webpack-inline-source-plugin,专门用来处理入口文件内联的
$ npm install --save-dev html-webpack-inline-source-plugin
该插件的使用很简单,使用require()语句引入后,在插件plugins()新建一个html-webpack-inline-source-plugin对象,然后在html-webpack-plugin对象中添加inlineSource属性即可
inlineSource: '.(js|css)$' // embed all javascript and css inline
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); module.exports = { entry: './entry.js', output:{ path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, plugins: [ new HtmlWebpackPlugin({ inlineSource: '.(js|css)$' }), new HtmlWebpackInlineSourcePlugin() ] }
结果如下
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> </head> <body> <script type="text/javascript">/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { document.write('It works.') /***/ }) /******/ ]);</script></body> </html>
babel
下面使用babel来进行es最新标准的代码向es5代码的转换,首先需要安装babel核心程序,及babel-loader
npm install babel-loader babel-core
在使用babel-loader进行代码转换之前,要先了解到ecmascript标准变化很快,且浏览器支持情况不同。所以,出现了'es2015'、'es2016'、'es2017'、'latest'、'env(new)'等多个不同的标准。这时,要需要来选择从哪个标准进行转换,需要安装插件babel-preset-env
npm install babel-preset-env
在 webpack 配置对象中,需要添加 babel-loader 到 module 的 loaders 列表中。webpack的配置文件如下所示
const path = require('path');
module.exports = { entry:{ app:'./src/app.js', }, output:{ path:path.resolve(__dirname,'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }
关于path有两种写法,除了上面的配置文件的写法外,另一种写法如下所示。但是,尽量不要使用__dirname + '/src'的写法,在某些参数中,该写法无法生效
path: __dirname + "/src"
在命令行中运行webpack命令进行打包,打包过程如下
打包前的文件为app.js,内容如下
() => { return a + b; }; Array.from('1,2,3'); new Set;
打包后的文件为app.bundle.js,主要内容如下
/******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; (function () { return a + b; }); Array.from('1,2,3'); new Set(); /***/ }) /******/ ]);
经过babel转换后的js文件存在两个问题:
1、打包速度较慢
2、部分ES2017的新语法没有转换为ES5的代码
下面对这两个问题分别进行处理
【打包速度】
loader的test属性表示该loader必须满足的条件,上面代码中使用/.js$/ 来匹配,也许会去编译 node_modules 目录或者其他不需要的源代码。这样会大大增加webpack的编译时间
要排除 node_modules,就要使用 loaders 配置的 exclude 选项,表示哪些除外,exclude:/node_modules/
module.exports = { entry:{ app:'./src/app.js', }, output:{ path:__dirname+'/src/', filename: '[name].bundle.js' }, module: { rules: [{ test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }
[注意]exclude除了支持正则表达式外,还支持字符串形式,写法如下。如果用__dirname +'/node_modules'的形式则不会生效
const path = require('path'); exclude:path.resolve(__dirname, "node_modules")
打包过程如下
当node-modules文件部分较大时,速度提升会更明显
除了exclude选项,还可以使用include选项,能够明确被打包的文件时,使用include将使打包速度更快
module.exports = { entry:{ app:'./src/app.js', }, output:{ path:__dirname+'/src/', filename: '[name].bundle.js' }, module: { rules: [{ test: /.js$/, include: /src/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }
[注意]include的另一种写法如下所示
const path = require('path'); include: path.resolve(__dirname, 'src')
打包过程如下
耗费时间有所减小
cacheDirectory选项值默认为false,当为true时,指定的目录将用来缓存 loader 的执行结果。之后的 webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel 重新编译过程
const path = require('path'); module.exports = { entry: { app: './src/app.js', }, output: { path: path.resolve(__dirname, 'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /.js$/, include: path.resolve(__dirname, 'src'), use: { loader: 'babel-loader', options: { presets: ['env'], cacheDirectory:true } } }] }, }
耗费时间减少了100ms,效果很好
解决了babel编译速度后,下面来解决ES新语法不被转换的问题
【babel-polyfill】
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign
)都不会转码。
举例来说,ES6在Array
对象上新增了Array.from
方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill。
babel-polyfill是一个全局垫片,为开发应用准备的
npm install babel-polyfill
在脚本头部加入下面代码即可使用
import 'babel-polyfill';
app.js的文件内容如下
import 'babel-polyfill'; () => { return a + b; }; Array.from('1,2,3'); new Set;
由下图所示,转换后的文件大小超过了200kb
【babel-plugin-transform-runtime】
相当于babel-polyfill来说,babel-plugin-transform-runtime更加适用,它是一个局部垫片,为开发框架准备
npm install babel-plugin-transform-runtime babel-runtime
app.js文件如下所示
() => { return a + b; }; Array.from('1,2,3'); new Set;
配置文件如下所示
const path = require('path'); module.exports = { entry: { app: './src/app.js', }, output: { path: path.resolve(__dirname, 'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /.js$/, include: path.resolve(__dirname, 'src'), use: { loader: 'babel-loader', options: { presets: ['env'], cacheDirectory:true, plugins: ['transform-runtime'] } } }] }, }
转换过程如下所示
转换后的文件app.bundle.js主要内容如下所示
(function () { return a + b; }); (0, _from2.default)('1,2,3'); new _set2.default();
CSS
在webpack入门博文中由介绍过CSS插件的简单使用,接下来将详细介绍
首先,要安装css-loader和style-loader,css-loader用于读取并加载css文件,style-loader将它插入到页面中
[特别注意]在处理css时,最好不要使用include、exclude等属性。include、exclude属性是加快babel转换速度的,和css没什么关系,而且会添乱
npm install css-loader style-loader
//app.js require('./css/common.css'); //common.css body{margin: 0;background-color: red} //webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', 'css-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({}) ] }
效果如下
【自动前缀】
页面加载CSS往往并不像上面的情况这么简单,需要处理很多问题,其中一个就是浏览器前缀问题。对于某些属性来说,比如transform,不同浏览器的版本对其支持程度不同,浏览器前缀也不同。这时,就需要能够根据实际情况,自动增加前缀,而postcss-loader就是这样的工具,而且功能要强大的多
首先,先安装postcss-loader
npm install postcss-loader
然后,安装postcss的自动前缀的插件autoprefixer
npm install autoprefixer
配置如下
//common.css body{transform: scale(0);background-color: red} //app.js require('./css/common.css'); //webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: {plugins: [require('autoprefixer')]} } ] } ] }, plugins: [ new HtmlWebpackPlugin({}) ] }
结果如下
如果css文件中出现@import,则有两种处理方式,一种是将postcss文件单独写成配置文件postcss.config.js
//common.css @import './flex.css'; body{transform: scale(0);background-color: red} //flex.css body{display:flex;} //app.js require('./css/common.css'); //webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', { loader: 'css-loader', options: {importLoaders: 1} }, 'postcss-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({}) ] } //postcss.config.js module.exports = { plugins:[require('autoprefixer')] }
结果如下
另一种需要安装postcss-import插件
npm install postcss-import
//common.css @import './flex.css'; body{transform: scale(0);background-color: red} //flex.css body{display:flex;} //app.js require('./css/common.css'); //webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', { loader: 'css-loader', options: {importLoaders: 1 } }, { loader: 'postcss-loader', options: {plugins: [ require('postcss-import'), require('autoprefixer') ] } } ] } ] }, plugins: [ new HtmlWebpackPlugin({}) ] }
结果如下
【sass】
首先,需要安装sass-loader及node-sass
[注意]关于node-sass安装的问题移步至此
npm install sass-loader node-sass
由于sass-loader中已经自带了关于@import处理的问题。所以,不需要css-loader及postcss-loader的额外处理
//layer.scss @import './flex.scss'; body{ background-color:green; div{ 400px; } } //flex.scss .flex{display:flex;} //app.js require('./components/layer/layer.scss'); //webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.scss$/, use:[ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: {plugins: [require('autoprefixer')]} }, 'sass-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({}) ] }
结果如下
【分离CSS】
默认地,CSS作为模块资源被打包到入口js文件中。有时,需要把CSS文件分离出来,这时就需要用到extract-text-webpack-plugin插件
npm install extract-text-webpack-plugin
该插件的配置如下
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/app.js', output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use:[ 'css-loader', { loader: 'postcss-loader', options: {plugins: [require('autoprefixer')]} }, 'sass-loader' ] }) } ] }, plugins: [ new HtmlWebpackPlugin({}), new ExtractTextPlugin("styles.css") ] }
结果如下,该插件将入口文件中引用的 *.css,移动到独立分离的 CSS 文件。因此,你的样式将不再内嵌到 JS bundle 中,而是会放到一个单独的 CSS 文件(即 styles.css)当中。 如果样式文件大小较大,这会做更快提前加载,因为 CSS bundle 会跟 JS bundle 并行加载
图片资源
webpack在处理图片、音乐、电影等资源文件时,需要使用file-loader
npm install file-loader
默认情况下,使用file-loader生成的文件的文件名就是文件内容的MD5哈希值并保留原始扩展名
file-loader的配置项如下所示
name [hash].[ext] 为文件配置自定义文件名模板 context this.options.context 配置自定义文件 context,默认为 webpack.config.js context publicPath __webpack_public_path__ 为文件配置自定义 public 发布目录 outputPath 'undefined' 为文件配置自定义 output 输出目录 useRelativePath false 如果希望为每个文件生成一个相对 url 的 context 时,应该将其设置为 true emitFile true 默认情况下会生成文件,可以通过将此项设置为 false 来禁止(例如,使用了服务端的 packages)
以引入图片资源例,有以下几种情况
1、通过css文件的background属性引入
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', 'css-loader' ] }, { test:/.(png|jpg|gif|svg)$/i, use:'file-loader' } ] }, plugins: [ new HtmlWebpackPlugin() ] } //entry.js require('./src/css/common.css'); //common.css body{background: url('../img/eg_bulbon.gif')}
结果如下
2、通过模板html文件img标签引入,这时需要使用${require('')}将相对路径包裹一次
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname,//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', 'css-loader' ] }, { test:/.(png|jpg|gif|svg)$/i, use:'file-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template:'template/template.html' }) ] } //template.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <img src="${require('../src/img/eg_bulbon.gif')}" alt=""> </body> </html>
结果如下
3、若模板使用ejs-compiled-loader插件,则无法使用${require('')}语句,需要使用HtmlWebpackPlugin传参来构造绝对路径
//webpack.config.js var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './entry.js', //入口文件 output: { path: __dirname + '/dist',//出口路径 filename: 'js/[id]-[name]-[hash].js'//出口名称 }, module:{ rules:[ { test:/.css$/, use:[ 'style-loader', 'css-loader' ] }, { test:/.(png|jpg|gif|svg)$/i, use:'file-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template:'ejs-compiled-loader!template/template.html', file:__dirname }) ] } //template.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div> <% include template/header.html %> </div> </body> </html> //header.html <img src="<%=htmlWebpackPlugin.options.file%>srcimgeg_bulbon.gif" alt="">
结果如下
【file-loader参数】
文件名模板占位符有如下几种
[ext] 资源扩展名 [name] 资源的基本名称 [path] 资源相对于 context 查询参数或者配置的路径 [hash] 内容的哈希值,默认为十六进制编码的 md5 [<hashType>:hash:<digestType>:<length>] 可选配置 其他的 hashType, 即 sha1, md5, sha256, sha512 其他的 digestType, 即 hex, base26, base32, base36, base49, base52, base58, base62, base64 length 字符的长度 [N] 当前文件名按照查询参数 regExp 匹配后获得到第 N 个匹配结果
{ test:/.(png|jpg|gif|svg)$/i, use:[{ loader:'file-loader', options: { name:'[name]-[hash:5].[ext]' } }] }
或者
{ test:/.(png|jpg|gif|svg)$/i, use:['file-loader?name=[name]-[hash:5].[ext]'] }
结果如下
【url-loader】
url-loader功能类似于file-loader,但是在文件大小(单位byte)低于指定的限制时,可以返回一个dataURL
可以通过传递查询参数(query parameter)来指定限制(默认为不限制)
如果文件大小超过限制,将转为使用 file-loader,所有的查询参数也会传过去
npm install url-loader
图片的大小为1.1kb,下面将限制设置为2000,则图片将以base64格式传递
{ test:/.(png|jpg|gif|svg)$/i, use:['url-loader?limit=2000'] }
结果如下
如果将限制大小设置为1000,图片以src的形式传递
{ test:/.(png|jpg|gif|svg)$/i, use:[{ loader:'url-loader', options: { limit:1000, name:'[name]-[hash:5].[ext]' } }] }
【image-webpack-loader】
使用image-webpack-loader来压缩图片
npm install image-webpack-loader
image-webpack-loader的配置项如下
options: { mozjpeg: { progressive: true, quality: 65 }, optipng: { enabled: false, }, pngquant: { quality: 80, speed: 4 }, gifsicle: { interlaced: false, }, webp: { quality: 75 } }
插件一张大小为4.1kb的名称为'm.jpg'的图片,配置如下
{ test:/.(png|jpg|gif|svg)$/i, use:[ 'url-loader?limit=1000&name=[name]-[hash:5].[ext]', 'image-webpack-loader' ] }
结果如下所示,生成大小为3.28kb,名称为'm-c7083.jpg'的图片
【雪碧图】
在webpack中自动生成雪碧图,需要使用postcss-sprits插件
npm install postcss-sprites
配置非常简单
"plugins": { "postcss-sprites": { spritePath: 'dist/assets/imgs/sprites/' } } }
加载第三方库
如果是加载的远程CDN库,则在HTML文件内直接使用script标签引入即可
<script src="https://cdn.bootcss.com/jquery/3.3.1/core.js"></script>
这样,在文件中可以直接使用jQuery
如果jQuery是通过npm保存到本地,则需要使用ProvidePlugin插件来自动加载模块,而不必到处 import
或 require
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' })
然后在我们任意源码中:
// in a module $('#item'); // <= 起作用 jQuery('#item'); // <= 起作用 // $ 自动被设置为 "jquery" 输出的内容
如果jQuery是保存在一个自定义的目录中的,则需要还需要设置别名
resolve:{ alias:{ jquery$:path.resolve(__dirname,'src/libs/jquery.min.js') } }
除了使用providePlugin,还可以使用imports-loader
module: { rules: [ { test: path.resolve(__dirname,"src/app.js"), use: [ loader: 'imports-loader', options: {$:'jquery'} ] } ] }
代理远程接口
使用webpack-dev-server的proxy功能,可以代理远程接口。实际上,它使用的是http-proxy-middleware插件
常用参数如下
target:代理指向的地址 changeOrigin:改变源URL(默认false) headers:设置http请求头 pathRewrite:重定向接口请求
logLevel:控制台显示信息
在 localhost:3000
上有后端服务的话,可以这样启用代理:
proxy: { "/api": "http://localhost:3000" }
如果服务器给出500错误,则需要添加changeOrigin
proxy: { "/api": { target: "http://localhost:3000", changeOrigin: true } }
实用配置
下面将使用webpack搭建一个实用的开发环境
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/app.js',//入口文件 output:{ path: __dirname,//出口路径 filename: 'js/[name].bundle.js'//出口名称 }, module:{ rules:[ { test:/.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use:[ 'css-loader', { loader: 'postcss-loader', //自动添加前缀 options: {plugins: [require('autoprefixer')]} }, 'sass-loader' ] }) }, { test:/.js$/, include:/./src/, use:{ loader: 'babel-loader', //将最新标准的js代码翻译为es5代码 options:{presets: ['env']} } }, { test:/.(png|jpg|gif|svg)$/i, use:[ //当图片大小大于1000byte时,以[name]-[hash:5].[ext]的形式输出 //当图片大小小于1000byte时,以baseURL的形式输出 'url-loader?limit=1000&name=[name]-[hash:5].[ext]', //压缩图片 'image-webpack-loader' ] } ] }, plugins: [ //使用模板生成html文件 new HtmlWebpackPlugin({template:'ejs-compiled-loader!template/template.html'}), //分离出css到style.css new ExtractTextPlugin("style.css") ] }
webpack配置文件
1、webpack可以处理js,json文件,不能处理其他文件
2、生产环境比开发环境多一个压缩js代码
3、生产环境和开发环境可将ES6模块编译成浏览器能识别的模块
/*webpack.config.js*/ //resolve用来拼接绝对路径的方法 const {resolve} = require('path'); module.exports = { entry: './src/js/index.js', //入口文件,webpack从这里开始打包 output: { filename: 'build.js', //输出文件名 path: resolve(__dirname, 'build') //输出路径,一般采用绝对路径 //__dirname nodejs的变量,代表当前文件目录的绝对路径 }, //loader处理那些非JavaScript文件 module: { rules:[ //详细loader配置,不同文件配置不同loader ] }, plugins: [ //插件,执行更大更复杂的任务 ], //打包模式 mode: 'development' //development:开发环境,production:生产环境
HTML配置
/*
loader:1、下载 2、使用(配置loader)
plugins:1、下载 2、引入 3、使用
*/
const {resolve} = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry:'./src/index.js', output:{ filename:'build.js', path:resolve(__dirname, 'build') }, module:{ rules:[ ] }, plugins:[ //html-webpack-plugin //功能:默认创建一个空的HTML,自动引入打包输出的所有资源(JS/Css) //需求:需要有结构的HTML文件 new HtmlWebpackPlugin({ // 复制./src/index.html文件,并自动引入打包输出的所有资源 template: './src/index.html', // 压缩html minify: { // 移除空格 collapseWhitespace: true, // 移除注释 removeComments: true, }, } ) ], mode: 'development' }
CSS配置
const {resolve} = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 复用loader /*css兼容性处理:postcss-->postcss-loader postcss-preset-env (package.josn) "browserslist": { //开发环境-->设置node环境变量:process.env.NODE_ENV = development "development": [ "last 1 chrome version", 兼容最近版本的浏览器 "last 1 firefox version", "last 1 safari version" ], //生产环境,默认看生产环境 "production": [ ">0.2%", 兼容99.8%的浏览器 "not dead", 不要已死的浏览器 "not op_mini all" 不要op_mini ] } 帮postcss找到package.josn中browserslist里面的配置,通过配置加载指定的css兼容性格式 */ // 使用loader的默认配置 ‘postcss-loader’ const commonCssLoader = [ MiniCssExtractPlugin.loader,//取代style-loader,提取js中的css成单独文件 'css-loader', //将css文件变成commonjs模块加载到js中,里面的内容是样式字符串 { // 还需在package.json中定义browserslist loader: 'postcss-loader', options: { ident: 'postcss', plugins: () => { require('postcss-preset-env')(); }, }, }, ] module.exports = { entry: './src/js/index.js', output: { filename: 'js/build.js', path: resolve(__dirname, 'build'), }, module: { rules: [ { test: /.css$/, use: [ // use数组中执行顺序:从右到左、从下到上依次执行 // 'style-loader',创建style标签,将js中的样式资源插入进行,添加到head中生效 ...commonCssLoader ], }, { test: /.less$/, use: [ ...commonCssLoader, 'less-loader',// 将less文件编译成css文件 ], }, ] }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/build.css', }), new OptimizeCssAssetsWebpackPlugin(),// 压缩css new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ], mode: 'production' }
js配置
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/js/index.js', output: { filename: 'js/build.js', path: resolve(__dirname, 'build'), }, module: { rules: [ /* 语法检查: eslint-loader eslint 只检查自己写的源代码,不检查第三方库 设置检查规则: package.josn中 eslintConfig中设置 推荐使用airbnb规则 */ { test: /.js$/, exclude: /node_modules/, loader: 'eslint-loader', options: { // 自动修复 fix: true, }, }, /* js兼容性处理:babel-loader @babel/preset-env @babel/core 1.基本js兼容性处理 --> @babel/preset-env 问题:只能转换基本语法,promise等高级语法无法转换 2.全部js兼容性处理 --> @babel/polyfill 文件中导入即可 问题:只需解决部分兼容性问题。但是将所有兼容性代码全部引入,体积过大 3、需要做兼容性处理就做:按需加载 --> core-js */ { test: /.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { // 预设:指示babel做怎样的兼容性处理 presets: [ [ '@babel/preset-env', { // 按需加载 useBuiltIns: 'usage', // 指定core-js版本 corejs: { version: 3 }, // 指定兼容性做到哪个版本浏览器 targets:{ chrome: '60', firefox: '60', ie: '9', edge: '17', safari: '10' } } ] ], }, }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), ], mode: 'production', // 生产环境下会自动压缩js代码 };
图片处理
const HtmlWebpackPlugon = require('html-webpack-plugin') module.exports = { entry:'./src/index.js', output:{ filename:'build.js', path:`${__dirname}/build` }, module:{ rules:[ { test:/.less$/, //使用多个loader用use use:[ 'style-loader', 'css-loader', 'less-loader' ] },{ //处理图片资源 // 问题:默认处理不了HTML中img图片 test: /.(jpg|png|gif)$/, // 使用一个loader // 下载url-loader file-loader loader: 'url-loader', options: { // 图片大小小于8kb,就会被base64处理 // 优点:减少请求数量(减轻服务器压力) // 缺点:图片体积会变大(文件请求速度更慢) limit: 8 * 1024, // esModule:false 关闭es6模块化,使用commonjs解析 // 给图片进行重命名 // [hash:10]:取图片的hash的前十位 // [ext]取文件原来的扩展名 name:'[hash:10].[ext]' } }, { test:/.html$/, // 处理HTML文件的img图片(负责引入img,从而能被url-loader处理) loader:'html-loader' } ] }, plugins:[ new HtmlWebpackPlugon({ template:'./src/index.html' }) ], mode:'development' }
其他资源
const { resolve } = require('path'); const HtmlWebpackPlugin = require ('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'build.js', path: resolve( __dirname, 'build' ) }, module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] }, //打包其他资源(除了html/css/js以外的资源) { // 排除html/css/js资源 exclude:/.(css|js|html|jpg|png|gif)$/,//url-loader也可以用 loader:'file-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development' }
devServer自动打包编译
const { resolve } = require('path'); const HtmlWebpackPlugin = require ('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'build.js', path: resolve( __dirname, 'build' ) }, module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] }, //打包其他资源(除了html/css/js以外的资源) { // 排除html/css/js资源 exclude:/.(css|js|html)$/,//url-loader也可以用 loader:'file-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development', //开发服务器devsever:用来自动编译,自动打开浏览器,自动刷新浏览器 // 特点:只会在内存中编译打包,不会有任何输出(不会生成build文件夹) // 启动devserver指令为:npx webpack-dev-server devServer: { // 构建后的项目路径 contentBase: resolve(__dirname,'build'), //启动gzip压缩 compress: true, // 端口号 port: 3000, // 自动打开浏览器 open: true } }
开发环境配置
/*
开发环境配置:代码可运行
运行指令:
webpack 会将打包结果输出
npx webpack-dev-server 只会在内存中编译打包,没有输出
*/
const {resolve} = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry:'./src/index.js', output: { filename: 'build.js', path: resolve(__dirname, 'build') }, module:{ rules: [ { test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, { test:/.css$/, use: ['style-loader', 'css-loader'] }, { test:/.(jpg|png|gif)$/, loader: 'url-loader', options: { linit: 8*1024, name:'[hash:10].[ext]', exModule: false//关闭es6模块化 }, // outputPath:'img' 输出到build/img文件夹 }, { //处理html中的img test: /.html$/, loader: 'html-loader' }, { exclude: /.(html|css|js|jpg|png|gif|less)$/, loader:'file-loader', options: { name:'[hash:10].[ext]' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'build'), compress: true, //优化 port: 3000, open: true }, }
生产环境配置
const { resolve } = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); // 定义node环境变量,决定使用browserslist的哪个环境 process.env.NODE_ENV = 'production'; // 复用loader const commonCssLoader = [ MiniCssExtractPlugin.loader, 'css-loader', { // 还需在package.json中定义browserslist loader: 'postcss-loader', options: { ident: 'postcss', plugins: () => { require('postcss-preset-env')(); }, }, }, ] /* 正常来讲,一个文件只能被一个loader处理 当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序: 先执行eslint再执行babel */ module.exports = { entry: './src/js/index.js', output: { filename: 'js/build.js', path: resolve(__dirname, 'build'), }, module: { rules: [ { test: /.css$/, use: [ ...commonCssLoader ], }, { test: /.less$/, use: [ ...commonCssLoader, 'less-loader', ], }, { // 在package.josn中eslintConfig --> airbnb test: /.js$/, exclude: /node_module/, // 优先执行 enforce: 'pre', loader: 'eslint-loader', options: { fix: true } }, { // 在package.josn中eslintConfig --> airbnb test: /.js$/, exclude: /node_module/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '50', }, }, ], ], } }, { test: /.(jpg|png|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', outputPath: 'imgs', esModule: false } }, { test: /.html$/, loader: 'html-loader' }, { exclude: /.(js|css|less|html|jpg|png|gif)$/, loader: 'file-loader', options: { outputPath: 'media' } } ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/build.css', }), new OptimizeCssAssetsWebpackPlugin(), new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ], mode: 'production' };
Webpack配置区分开发环境和生产环境
在项目开发的时候,我们通常会将程序分为开发环境和生产环境(或者叫线上环境),开发环境通常指的是我们正在开发的这个阶段所需要的一些环境配置,也就是方便我们开发人员调试开发的一种环境;生产环境通常指的是我们将程序开发完成经过测试之后无明显异常准备发布上线的环境,也可以理解为用户可以正常使用的就是生产环境;
当然开发环境和生产环境在配置方面的需求是不一样的,但是有共同点:
开发环境的需求:
模块热更新 (本地开启服务,实时更新)
sourceMap (方便打包调试)
接口代理 (配置proxyTable解决开发环境中的跨域问题)
代码规范检查 (代码规范检查工具)
生产环境的需求:
提取公共代码
压缩混淆(压缩混淆代码,清除代码空格,注释等信息使其变得难以阅读)
文件压缩/base64编码(压缩代码,减少线上环境文件包的大小)
去除无用的代码
开发环境和生产环境的共同需求:
同样的入口
同样的代码处理(loader处理)
同样的解析配置
在我们搭建好Vue-cli脚手架之后,我们的build文件夹会分别自动的生成webpack.base.conf.js、webpack.dev.conf.js、webpack.prod.conf.js三个webpack配置文件;
webpack.base.conf.js:webpack的开发环境和生产环境的共有配置(开发环境和生产环境都是需要执行的配置)
webpack.dev.conf.js:webpack的开发环境的特有配置(只在开发环境中执行,生产环境中不执行)
webpack.prod.conf.js:webpack的生产环境的特有配置(只在生产环境中执行,开发环境中不执行)
我们为什么要区分开发环境和生产环境呢?
因为一个项目的开发过程中肯定不会是一个版本开发完之后就立马上线,开发是必需,上线是目的;在开发的过程中会有各种各样的问题,比如开发环境中跨域、开发环境和生产环境因环境不同而产生的未知奇葩错误等等都是会时常发生的,我们区分环境的目的就是为了让开发人员在开发的过程中可以方便调试,保持高效的开发;让程序在生产环境中正常有效的运行;
webpack.base.conf.js配置
const path = require('path'); //清除build/dist文件夹文件 const CleanWebpackPlugin = require('clean-webpack-plugin'); //生成创建Html入口文件 const HtmlWebpackPlugin = require('html-webpack-plugin'); //将css提取到单独的文件中 const MiniCssExtract = require('mini-css-extract-plugin'); //css压缩 const OptimizeCss = require('optimize-css-assets-webpack-plugin'); //压缩js文件 const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); //引入webpack const webpack = require('webpack'); module.exports = { //webpack 入口文件 entry: './src/index.js', //webpack 输出文件配置 output: { //输出文件路径 path: path.resolve(__dirname, 'dist'), //输出文件名 filename: 'k-editor.[hash:8].js', }, //配置插件 plugins: [ //使用插件清除dist文件夹中的文件 new CleanWebpackPlugin({ path: './dist' }), //使用插件生成Html入口文件 new HtmlWebpackPlugin({ //模板文件路径 template: "./src/index.html", //模板文件名 filename: "index.html", minify: { removeAttributeQuotes: true, //删除双引号, collapseWhitespace: true, //压缩成一行, }, hash: true }), //提取css到style.css中 new MiniCssExtract({ filename: 'style.css' }), ], resolve: { // modules: [path.resolve('node_modules')],//只在当前目录下查找 alias: { //别名 'bootstrap': 'bootstrap/dist/css/bootstrap.css', }, // mainFields: ['style', 'main'],//优先寻找style, // mainFiles: [],//入口文件的名字,默认index.js // extensions: ['js', 'css', 'json', 'vue']//扩展名顺序 }, //loader加载器模块配置 module: { rules: [ { //正则表达式匹配.css为后缀的文件 test: /.css$/, //使用loader use: [ MiniCssExtract.loader, 'css-loader', { loader: "postcss-loader" }, ] //正则表达式匹配.less为后缀的文件 //使用lodaer来处理 }, { test: /.less$/, use: [ MiniCssExtract.loader, 'css-loader', { loader: "postcss-loader" }, 'less-loader' ] }, /* { test: /.js$/, //不包括node_modules exclude: /node_modules/, use: [{ loader: "eslint-loader", options: { enforce: 'pre' //强制更改顺序,pre 前 post 后 } }], },*/ { test: /.js$/, //普通的loader //不包括node_modules exclude: /node_modules/, use: [{ loader: "babel-loader" }] }, { test: /.html$/, use: ['html-withimg-loader'] }, { test: /.(gif|png|jpg)$/, use: [{ loader: "url-loader", options: { //图片小于10kb就是图片地址,大于正常打包成base64格式编码 limit: 10000, //输出路径 outputPath: 'img/' } }] } ] }, };
webpack.dev.conf.js:
//引入webpack-merge插件进行合并 const {merge} = require('webpack-merge'); //引入webpack.base.conf.js文件 const base = require('./webpack.base.conf'); //引入webpack const webpack = require('webpack'); //进行合并,将webpack.base.conf.js中的配置合并到这 module.exports = merge(base, { //模块参数 mode: 'development', devServer: { contentBase: './dist', //端口号 port: '8383', inline: true, historyApiFallback: true,//在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html hot: true//允许热加载 }, //启用source-map方便调试 devtool: 'source-map', plugins: [ //定义全局变量 new webpack.DefinePlugin({ //这里必须要解析成字符串进行判断,不然将会被识别为一个变量 DEV: JSON.stringify('dev') }) ] });
webpack.prod.conf.js:
const {merge} = require('webpack-merge'); const base = require('./webpack.base'); const path = require('path'); const OptimizeCss = require('optimize-css-assets-webpack-plugin'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const webpack = require('webpack'); module.exports = merge(base, { mode: 'production', optimization: { minimizer: [ //压缩CSS代码 new OptimizeCss(), //压缩js代码 new UglifyJsPlugin({ //启用文件缓存 cache: true, //使用多线程并行运行提高构建速度 parallel: true, //使用 SourceMaps 将错误信息的位置映射到模块 sourceMap: true }) ] }, plugins:[ //使用插件定义全局变量DEV new webpack.DefinePlugin({ DEV:JSON.stringify('production') }) ] });
最后在配置一下package.json文件就可以了:
"scripts": { "test": "npm run test", "dev": "webpack-dev-server --config webpack.dev.js", "build": "webpack --config webpack.prod.js" },
如何区分开发环境和生产环境呢?
在node中,我们有一个对象process对象,它里面包括的一些信息,env和它的一些属性,当然NODE_ENV是我们自己加上去的自定义属性,用来区分环境变量,也就是通过这个变量来进行区别是开发环境还是生产环境;但是有个问题,不同电脑上设置的方式是不一样的,所以cross-env就来了,它可以跨平台设置环境和使用环境变量。
npm install cross-env
我们在webpack.base.conf.js文件中修改代码:
const NODE_ENV=process.env.NODE_ENV; console.log(NODE_ENV);
然后我们修改package.json文件:
//--config是可以设置我们执行哪个webpack文件,默认是执行webpack.config.js,但是我们现在修改文件名了,所以我们要设置一下 "build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js", "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js"
就这样,我们就实现了利用webpack来区分开发环境和生产环境,当我们用npm run dev运行的时候就是开发环境,当我们运行npm run build的时候就是构建生产环境打包;
webpack-merge 配置抽离
前置
如果你曾使用 webpack 构建应用,就会知道如果把所有配置都写在 webpack.config.js
中那将是灾难。正如你所见,我现在使用的这套博客园皮肤是使用 gulp 构建的,如果你不熟悉 gulp, 那你肯定熟悉 webpack. 下面将介绍我使用这两个工具是如何抽离配置的,先从 webpack 开始.
webpack
原因
webpack 默认的 webpack.config.js
长这样:
module.exports = { entry: {}, output: {}, module: {} //... }
copy这里最让人头疼的就是 module
内的层层嵌套。例如,我稍稍处理 css 和 js 就会像下面这样:
module: { rules: [ { test: /.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, }, }, 'postcss-loader', ], }, { test: /.js$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, { loader: 'eslint-loader', options: { cache: true, }, }, ], }, ], },
如果再去区分生产环境和开发环境可能看起来更加混乱。好一点的做法是,抽离不同环境的 module 或者其他配置,根据环境来决定最终导出的项。但是无法改变的是这些东西都存在一个 webpack.config.js
文件中。如果应用程序需要使用大量的 loader, 会显得文件又长又混乱,需要修改一些配置时容易出错。寻找和出错都会浪费时间.
webpack-merge
npm i -D webpack-merge
Webpack-merge 提供了一个函数,该函数将数组串联并合并创建新对象的对象。如果遇到函数,它将执行它们,通过算法运行结果,然后再次将返回的值包装在函数中。
语法
// 默认的方式 const output = merge (object1, object2, object3, ...); // 数组对象 // 这适用于所有可用的功能。 const output = merge ([object1, object2, object3]); // 右边优先 const output = merge ( { fruit: "apple", color: "red" }, { fruit: "strawberries" } );
一般使用默认的方式就够了,深入了解 Webpack-merge. 接下来不在使用
webpack.config.js
, 在项目根目录新建 config 文件夹。文件夹下新建:- webpack.base.js 公共的配置
- webpack.dev.js 开发环境配置
- webpack.prod.js 生产环境配置
webpack.base.js
const path = require ("path") module.exports = { entry: { // 这里是多入口 index: "./src/main.js", reacg: "./src/themes/reacg/index.js" //... }, output: { filename: "[name].min.js", path: path.join (__dirname, "..", "dist") }, resolve: { alias: { "@": path.resolve ("src") } } }
这里需要注意的一点是 output.path
需要处理一下路径.path.join (__dirname,"..","dist")
, 这样就能够和原来一样将打包得到的 dist 目录输出到根目录.
这句代码的意思是获取当前绝对路径的上一层路径,就是项目的根目录了。另外的 webpack.dev.js
和 webpack.prod.js
根据项目需要分别配置就可以了。这样如果再去添加或修改一些配置就能一目了然了。最后还需要更改一下 package.json
中的 script
:
"scripts": { "start": "webpack-dev-server --config config/webpack.dev.js", "build": "webpack --config config/webpack.prod.js" },
文章内容转载,参考链接:
https://www.cnblogs.com/xiaohuochai/p/7007391.html