1、介绍
Webpack是⼀个打包模块化JavaScript的⼯具,它会从⼊⼝模块出发,
识别出源码中的模块化导⼊语句,递归地找出⼊⼝⽂件的所有依赖,将⼊
⼝和其所有的依赖打包到⼀个单独的⽂件中
是⼯程化、⾃动化思想在前端开发中的体现
2、安装
全局安装(不推荐)
npm install webpack webpack-cli -g
webpack -v
npm uninstall webpack webpack-cli -g
|
全局安装webpack,这会将你项⽬中的webpack锁定到指定版本,造成不
同的项⽬中因为webpack依赖不同版本⽽导致冲突,构建失败
项目安装(推荐)
npm i -D webpack
npm i -D webpack@<version>
npm i -D webpack@beta
npm i -D webpack-cli
|
3、webpack配置核心概念
零配置是很弱的,特定的需求,总是需要⾃⼰进⾏配置
webpack有默认的配置⽂件,叫webpack.config.js,我们可以
对这个⽂件进⾏修改,进⾏个性化配置
- 使⽤默认的配置⽂件:webpack.config.js
- 不使⽤⾃定义配置⽂件: ⽐如webpackconfig.js,可以通过–
config webpackconfig.js来指定webpack使⽤哪个配置⽂件来
执⾏构建
webpack.config.js配置基础结构
module.exports = { entry: "./src/index.js", output: "./dist", mode: "production", module: { rules: [ { test: /\.css$/, use: "style-loader" } ] }, plugins: [] };
|
3.1-entry
指定webpack打包⼊⼝⽂件:Webpack 执⾏构建的第⼀步将从
Entry 开始,可抽象成输⼊
entry:{ main: './src/index.js' }
entry:"./src/index.js"
entry:{ index:"./src/index.js", login:"./src/login.js" }
|
3.2 output
打包转换后的⽂件输出到磁盘位置:输出结果,在 Webpack 经过⼀
系列处理并得出最终想要的代码后输出结果。
output: { filename: "bundle.js", path: path.resolve(__dirname, "dist") },
output: { filename: "[name][chunkhash:8].js", path: path.resolve(__dirname, "dist") },
|
3.3-mode
Mode⽤来指定当前的构建环境
设置mode可以⾃动触发webpack内置的函数,达到优化的效果
development: 会将DefinePlugin中的 process.env.NODE_DEV的值设置为
development。启用NameChunksPlugin和NameModulesPlugin。
production: 会将DefinePlugin中的 process.env.NODE_DEV的值设置为
production。启用FlagDepenndencyUsagePlugin, FlagIncludedChunksPlugin,
ModuleConcatenationPlugin等
none 退出任何默认优化选项
3.4-loader
Webpack 默认只⽀持.json 和 .js模块 不⽀持 不认识其他格式的模
块
模块解析,模块转换器,⽤于把模块原内容按照需求转换成新内
容。
webpack是模块打包⼯具,⽽模块不仅仅是js,还可以是css,图⽚
或者其他格式,但是webpack默认只知道如何处理js和JSON模块,那么其他格式的
模块处理,和处理⽅式就需要loader了
常见loader
style-loader css-loader less-loader sass-loader ts-loader //将Ts转换成js babel-loader//转换ES6、7等js新特性语法 file-loader//处理图⽚⼦图 eslint-loader ...
|
3.5-module
模块,在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。
Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
当webpack处理到不认识的模块时,需要在webpack中的module
处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处
理。
module:{ rules:[ { test:/\.xxx$/, use:{ loader: 'xxx-load' } } ] }
|
下面的配置,包括了对图片,样式文件,字体等的处理
module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"], }, { test: /\.less$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: true, }, }, { loader: "postcss-loader", }, "less-loader", ], }, { test: /\.(png|jpe?g|gif)$/, use: { loader: "url-loader", options: { name: "[name]_[hash:6].[ext]", outputPath: "images/", limit: 12 * 1024, }, }, }, { test: /\.(eot|ttf|woff|woff2|svg)$/, use: "file-loader" } ], },
|
多个loader执行是有顺序的
loader执行从右到左,从下到上
3.6 Plugins
- 作⽤于webpack打包整个过程
- webpack的打包过程是有(⽣命周期概念)钩⼦
plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,
类似于⽣命周期的概念
扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改
变构建结果或做你想要的事情
常用的有下面的插件
HtmlWebpackPlugin (自动生成html文件,并将打包的js模块引入到该html)
clean-webpack-plugin (自动删除上一次打包文件)
mini-css-extract-plugin (将css抽离成单独的文件) ...
|
plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "css/[name]-[contenthash:8].css", }), new HtmlWebpackPlugin({ title: "首页", template: "./src/index.html", filename: "index.html", }), ],
|
sourceMap
源代码与打包后的代码的映射关系,通过sourceMap定位到源代
码。
在dev模式中,默认开启,关闭的话 可以在配置⽂件⾥
eval:速度最快,使⽤eval包裹模块代码,
source-map: 产⽣.map⽂件
cheap:较快,不包含列信息
Module:第三⽅模块,包含loader的sourcemap(⽐如jsx to js ,
babel的sourcemap)
inline: 将.map作为DataURI嵌⼊,不单独⽣成.map⽂件
配置推荐:
devtool:"cheap-module-eval-source-map",
devtool:"cheap-module-source-map",
|
WebpackDevServer(提升开发效率的利器)
每次改完代码都需要重新打包⼀次,打开浏览器,刷新⼀次,很麻
烦,我们可以安装使⽤webpackdevserver来改善这块的体验
安装
npm install webpack-dev-server -D
|
配置
修改下package.json
"scripts": { "server": "webpack-dev-server" },
|
在webpack.config.js配置
devServer: { contentBase: "./dist", open: true, port: 8081 },
|
启动
启动服务后,会发现dist⽬录没有了,这是因为devServer把打包后
的模块不会放在dist⽬录下,⽽是放到内存中,从⽽提升速度
本地mock,解决跨域:
联调期间,前后端分离,直接获取数据会跨域,上线后我们使⽤
nginx转发,开发期间,webpack就可以搞定这件事
启动⼀个服务器,mock⼀个接⼝:
const express = require('express') const app = express() app.get('/api/info', (req,res)=>{ res.json({ name:'foo', age:5, msg:'welcome' }) }) app.listen('9099')
|
修改webpack.config.js 设置服务器代理
proxy: { "/api": { target: "http://localhost:9099" } }
|
Hot Module Replacement (HMR:热模块替换)
不⽀持抽离出的css 我们要使⽤css-loader
启动HMR
devServer: { contentBase: "./dist", open: true, hot:true, hotOnly:true },
|
配置⽂件头部引⼊webpack, 同时在插件配置处添加插件代码
const path = require("path"); const HtmlWebpackPlugin = require("html-webpackplugin"); const CleanWebpackPlugin = require("clean-webpackplugin"); const webpack = require("webpack"); plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "src/index.html" }), new webpack.HotModuleReplacementPlugin() ],
|
注意启动HMR后,css抽离会不⽣效,还有不⽀持contenthash,chunkhash
处理js模块HMR
需要使⽤module.hot.accept来观察模块更新 从⽽更新
function counter() { var div = document.createElement("div"); div.setAttribute("id", "counter"); div.innerHTML = 1; div.onclick = function () { div.innerHTML = parseInt(div.innerHTML, 10) + 1; }; document.body.appendChild(div); } export default counter;
function number() { var div = document.createElement("div"); div.setAttribute("id", "number"); div.innerHTML = 13000; document.body.appendChild(div); } export default number;
import counter from "./counter"; import number from "./number"; counter(); number(); if (module.hot) { module.hot.accept("./b", function () { document.body.removeChild(document.getElementById("number")); number(); }); }
|
Bable处理ES6
Babel是JavaScript编译器,能将ES6代码转换成ES5代码,让我们
开发过程中放⼼使⽤JS新特性⽽不⽤担⼼兼容性问题。并且还可以
通过插件机制根据需求灵活的扩展。
Babel在执⾏编译的过程中,会从项⽬根⽬录下的.babelrc JSON
⽂件中读取配置。没有该⽂件会从loader的options地⽅读取配
置。
安装
npm i babel-loader @babel/core @babel/preset-env -D
|
1.babel-loader是webpack 与 babel的通信桥梁,不会做把es6转成
es5的⼯作,这部分⼯作需要⽤到@babel/preset-env来做
2.@babel/preset-env⾥包含了es,6,7,8转es5的转换规则
配置
Webpack.config.js
{ test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, };
|
通过上⾯的⼏步 还不够,默认的Babel只⽀持let等⼀些基础的特性
转换,Promise等⼀些还有转换过来,这时候需要借助
@babel/polyfill,把es的新特性都装进来,来弥补低版本浏览器中
缺失的特性
@babel/polyfill
npm install --save @babel/polyfill
import "@babel/polyfill";
|
按需加载,减少冗余
会发现打包的体积⼤了很多,这是因为polyfill默认会把所有特性注
⼊进来,假如我想我⽤到的es6+,才会注⼊,没⽤到的不注⼊,从
⽽减少打包的体积,可不可以呢
options: { presets: [ [ "@babel/preset-env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, corejs: 2, useBuiltIns: "usage", }, ], ]; }
|
useBuiltIns选项是babel 7的新功能,这个选项告诉babel如何
配置@babel/polyfill。 它有三个参数可以使⽤:
①entry: 需要
在webpack的⼊⼝⽂件⾥import “@babel/polyfill”⼀
次。babel会根据你的使⽤情况导⼊垫⽚,没有使⽤的功能不会被
导⼊相应的垫⽚。
②usage: 不需要import,全⾃动检测,但是要
安装@babel/polyfill。(试验阶段)
③false: 如果你import
“@babel/polyfill”,它不会排除掉没有使⽤的垫⽚,程序体积会
庞⼤。(不推荐)
我可以单独配置bable,而不是作为option选项
新建 .babelrc文件
{ presets: [ [ "@babel/preset-env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, corejs: 2, useBuiltIns: "usage", }, ], ]; }
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
|
基本配置文件
webpack.config.js
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const webpack = require("webpack");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = { entry: "./src/index.js", mode: "development", output: { path: path.resolve(__dirname, "./dist"), filename: "[name].js", publicPath: "https://cdn.kaikeba.com/assets/", }, module: { rules: [ { test: /\.css$/, include: path.resolve(__dirname, "./src"), use: ["style-loader", "css-loader"], }, { test: /\.less$/, include: path.resolve(__dirname, "./src"), use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: true, }, }, { loader: "postcss-loader", }, "less-loader", ], }, { test: /\.(png|jpe?g|gif)$/, include: path.resolve(__dirname, "./src"), use: { loader: "url-loader", options: { name: "[name]_[hash:6].[ext]", outputPath: "images/", limit: 12 * 1024, }, }, }, { test: /\.js$/, include: path.resolve(__dirname, "./src"), use: { loader: "babel-loader", }, }, ], }, resolve: { modules: [path.resolve(__dirname, "./node_modules")], alias: { "@": path.resolve(__dirname, "./src"), }, extensions: [".js", ".json"], }, externals: { lodash: "_", }, devtool: "cheap-inline-source-map", plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "css/[name]-[contenthash:8].css", }), new OptimizeCSSAssetsPlugin({ cssProcessor: require("cssnano"), cssProcessorOptions: { discardComments: { removeAll: true }, }, }), new HtmlWebpackPlugin({ title: "首页", template: "./src/index.html", filename: "index.html", minify: { removeComments: true, collapseWhitespace: true, minifyCSS: true, }, }), ], };
|