// webpack4中除了正常安装webpack以外,须要再单独安一个webpack-cli npm i webpack webpack-cli -D
webpack <entry> [<entry>] <output>css
直接输入webpack,默认执行: webpack.config.js or webpackfile.js文件;
若是想自定义文件名,运行:webpack --config webpack.conf.dev.jshtml
// ESmodule export default function(a,b){ return a+b } import sum from './sum' // common.js规范 module.exports = function(a,b){ return a-b } var minus = require('./minus') // AMD规范,多了两个bundle,异步加载 //amd规范 define(function(require, factory) { 'use strict'; return function(a,b){ return a*b } }); require(['./muti'],function(muti){ console.log('muti,23,24='+muti(23,24)) }) console.log('sum,23,24='+sum(23,24)) console.log('minus,23,24='+minus(23,24))
npm install --save-dev babel-loader babel-core babel-preset-envnode
babel-loader:在import或加载模块时,对es6代码进行预处理,es6语法转化为es5语法。
babel-core:容许咱们去调用babel的api,能够将js代码分析成ast(抽象语法树),方便各个插件分析语法进行相应的处理.
babel-preset-env:为了告诉babel只编译批准的内容,至关于babel-preset-es2015, es2016, es2017及最新版本。经过它可使用最新的js语法。jquery
module.exports = { entry:{ app:'./app.js' }, output:{ filename:'[name].[hash:5].js' }, module:{ rules:[ { test:/\.js$/, use:{ loader:'babel-loader', options:{ presets:[ // 最新的版本 ['@babel/preset-env',{ targets:{// 支持目标,数据来源于‘can i use’网站 browsers:['> 1%','last 2 versions'] //chrome:'52' } }] ] } }, //排除相关文件 exclude:'/node_modules/' } ] } }
其中,exclude是定义不但愿babel处理的文件。targets是presets的一些预设选项,这里表示将js用于浏览器,只确保占比大于1%的浏览器的特性,主流浏览器的最新两个主版本。
更多与配置有关的信息,能够参考:
babel env preset设置,
browserlist预设置webpack
因为babel-preset配置选项较多,咱们通常能够在根目录下创建.babelrc文件,专门用来放置babel preset配置,这是一个json文件。能够将上述配置修改以下:git
//.bablerc文件 { "presets": [ ['env',{ "targets": { "browsers": ['> 1%', 'last 2 versions'] } }] ] } //原webpack.config.js文件 module: { rules: [ { test: /\.js$/, use: { loader: 'babel-loader' }, exclude: '/node_modules/' } ] }
在上面的babel配置中,babel只是将一些es6,es7-8的语法转换成符合目标的js代码,可是若是咱们使用一些特性或方法,好比Generator, Set, 或者一些方法。babel并不能转换为低版本浏览器识别的代码。这时就须要babel-polifill。es6
简单的说,polifill就是一个垫片,提供了一些低版本es标准对高级特性的实现。使用polifill的方法以下:github
npm install --save babel-polifill
而后在应用入口引入polifill,要确保它在任何其余代码/依赖声明前被调用。web
//CommonJS module require('babel-polyfill'); //es module import 'babel-polifill';
在webpack.config.js中,将babel-polifill加入entry数组中:chrome
entry: ["babel-polifill", "./app.js"]
相比于runtime-transform,polifill用于应用开发中。会添加相应变量到全局,因此会污染全局变量。
更多配置参考:babel-polifill
完整代码以下:
const path = require('path'); module.exports = { //entry为入口,webpack从这里开始编译 entry: [ "babel-polyfill", path.join(__dirname, './src/index.js') ], //output为输出 path表明路径 filename表明文件名称 output: { path: path.join(__dirname, './bundle'), filename: 'bundle.js' }, //module是配置全部模块要通过什么处理 //test:处理什么类型的文件,use:用什么,include:处理这里的,exclude:不处理这里的 module: { rules: [ { test: /\.js$/, use: ['babel-loader'], include: path.join(__dirname , 'src'), exclude: /node_modules/ } ] }, };
runtime transform也是一个插件,它与polifill有些相似,但它不污染全局变量,因此常常用于框架开发。
安装:
*npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime*
用法:
将下面内容添加到.bablerc文件中
{ "plugins": ["transform-runtime"] }
更多配置参考:bable-runtime-transform插件
1 . 安装处理 css 相关 loader
// css-loader让你能import css , style-loader能将css以style的形式插入 $ npm install --save-dev css-loader style-loader
module.exports = { plugins: [require('autoprefixer')] // 引用该插件便可了 }
而后在webpack里配置postcss-loader
module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] } ] } }
2 . 安装 less 相关
npm install --save-dev less less-loader
3 . 添加CSS3前缀
经过postcss中的autoprefixer能够实现将CSS3中的一些须要兼容写法的属性添加响应的前缀,这样省去咱们很多的时间
npm i postcss-loader autoprefixer -D
建立 postcss.config.js 加入如下代码
module.exports = { plugins: { 'postcss-cssnext': {} } }
4 . 实现
src/app.css
body { background: pink; }
src/app.js
import css from './app.css'; console.log("hello world");
// 处理顺序从右到左 less -> postcss -> css -> style { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }
5.用 mini-css-extract-plugin 把 CSS 分离成文件
npm install --save-dev mini-css-extract-plugin
rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] } ] new MiniCssExtractPlugin({ filename: "[name].css",// 指定打包后的css chunkFilename: "[id].css" }),
6.压缩与优化
打包 css 以后查看源码,咱们发现它并无帮咱们作代码压缩,这时候须要使用 optimize-css-assets-webpack-plugin 这个插件,它不只能帮你压缩 css 还能优化你的代码。
npm install --save-dev optimize-css-assets-webpack-plugin
const optimizeCss = require('optimize-css-assets-webpack-plugin'); //配置 optimization: { minimizer: [new OptimizeCSSAssetsPlugin()]; }
如上图测试用例所示,因为optimize-css-assets-webpack-plugin这个插件默认使用了 cssnano 来做 css 优化,
因此它不只压缩了代码、删掉了代码中无用的注释、还去除了冗余的 css、优化了 css 的书写顺序,优化了你的代码 margin: 10px 20px 10px 20px; =>margin:10px 20px;。同时大大减少了你 css 的文件大小。更多优化的细节见文档。
安装插件npm install --save-dev html-webpack-plugin 配置 webpack.config.js
npm install --save-dev html-webpack-plugin
const htmlWebpackPlugin = require('html-webpack-plugin'); ... plugins: [ new htmlWebpackPlugin({ filename: "index.html", //打包后的文件名 template: path.join(__dirname , "./src/index.html"), // 用哪一个html做为模板,在src目录下建立一个index.html页面当作模板来用 hash: true, // 会在打包好的bundle.js后面加上hash串 }) ],
若是须要多页面开发,能够这样写:
let path = require('path'); let HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // 多页面开发,怎么配置多页面 entry: { index: './src/index.js', login: './src/login.js' }, // 出口文件 output: { filename: '[name].js', path: path.resolve('dist') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', chunks: ['index'] // 对应关系,index.js对应的是index.html }), new HtmlWebpackPlugin({ template: './src/login.html', filename: 'login.html', chunks: ['login'] // 对应关系,login.js对应的是login.html }) ] }
$ npm i clean-webpack-plugin --save-dev
const CleanWebpackPlugin = require('clean-webpack-plugin'); ... plugins: [ ... new CleanWebpackPlugin(['bundle']) //传入清楚路径 ]
在webpack4以前,提取公共代码都是经过一个叫CommonsChunkPlugin的插件来办到的。到了4之后,内置了一个如出一辙的功能,并且起了一个好听的名字叫“优化”
下面咱们就来看看如何提取公共代码
// 假设a.js和b.js都同时引入了jquery.js和一个写好的utils.js // a.js和b.js import $ from 'jquery'; import {sum} from 'utils';
那么他们两个js中其中公共部分的代码就是jquery和utils里的代码了
能够针对第三方插件和写好的公共文件
module.exports = { entry: { a: './src/a.js', b: './src/b.js' }, output: { filename: '[name].js', path: path.resolve('dust') }, // 提取公共代码 + optimization: { splitChunks: { cacheGroups: { vendor: { // 抽离第三方插件 test: /node_modules/, // 指定是node_modules下的第三方包 chunks: 'initial', name: 'vendor', // 打包后的文件名,任意命名 // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包 priority: 10 }, utils: { // 抽离本身写的公共代码,utils这个名字能够随意起 chunks: 'initial', name: 'utils', // 任意命名 minSize: 0 // 只要超出0字节就生成一个新包 } } } + }, plugins: [ new HtmlWebpackPlugin({ filename: 'a.html', template: './src/index.html', // 以index.html为模板 + chunks: ['vendor', 'a'] }), new HtmlWebpackPlugin({ filename: 'b.html', template: './src/index.html', // 以index.html为模板 + chunks: ['vendor', 'b'] }) ] }
经过以上配置,能够把引入到a.js和b.js中的这部分公共代码提取出来,以下图所示
安装 webpack-dev-server
npm install --save-dev webpack-dev-server
webpack.config.js 添加配置
... devServer: { contentBase: path.join(__dirname, 'bundle'), //启动路径 host:'localhost', //域名,默认是localhost port: 8018, //端口号 open: true, //自动打开浏览器 hot: true //开启热更新 }
固然在npm run dev命令下,打包的文件存在于内存中,并不会产生在dist目录下
配置devServer的时候,若是hot为true,就表明开启了热更新
But这并没那么简单,由于热更新还须要配置一个webpack自带的插件而且还要在主要js文件里检查是否有module.hot
下面就让咱们直接看下代码是如何实现的
// webpack.config.js let webpack = require('webpack'); module.exports = { plugins: [ // 热更新,热更新不是刷新 new webpack.HotModuleReplacementPlugin() ], devServer: { contentBase: './dist', hot: true, port: 3000 } } // 此时还没完虽然配置了插件和开启了热更新,但实际上并不会生效 // index.js let a = 'hello world'; document.body.innerHTML = a; console.log('这是webpack打包的入口文件'); // 还须要在主要的js文件里写入下面这段代码 if (module.hot) { // 实现热更新 module.hot.accept(); }
$ npm install --save-dev file-loader
test: /\.(gif|png|jpe?g|svg)$/i, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', // 文件名和扩展名 outputPath: 'images/' } },
npm i file-loader url-loader -D
module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextWebpackPlugin.extract({ use: 'css-loader', publicPath: '../' }) }, { test: /\.(jpe?g|png|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192, // 小于8k的图片自动转成base64格式,而且不会存在实体图片 outputPath: 'images/' // 图片打包后存放的目录 } } ] } ] } }
html-loader: html 变成导出成字符串的过程当中,还能进行压缩处理(minimized)
$ npm install --save-dev html-loader
... { test: /\.(gif|png|jpe?g|svg)$/i, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', outputPath: 'images/' } }, ] }, // 下面几行才是 html-loader 的配置内容 { test: /\.html$/, use: [ { loader: 'html-loader', options: { minimize: true } }], } ...
image-webpack-loader:压缩图片文件
$ npm install image-webpack-loader --save-dev
{ test: /\.(gif|png|jpe?g|svg)$/i, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', outputPath: 'images/' } }, { loader: 'image-webpack-loader', options: { bypassOnDebug: true, } } ] }, { test: /\.html$/, use: [ { loader: 'html-loader', options: { minimize: true } }], }
在webpack的配置中,resolve咱们经常使用来配置别名和省略后缀名
module.exports = { resolve: { // 别名 alias: { $: './src/jquery.js' }, // 省略后缀 extensions: ['.js', '.json', '.css'] }, }
webpack 4 在项目中实际测了下,广泛能提升 20%~30%的打包速度。
首先你须要知道你目前打包慢,是慢在哪里。
咱们能够用 speed-measure-webpack-plugin 这个插件,它能监控 webpack 每一步操做的耗时。以下图:
能够看出其实大部分打包花费的时间是在Uglifyjs压缩代码。和前面的提高热更新的切入点差很少,查看source map的正确与否,exclude/include的正确使用等等。