一、webpack开始
- webpack是什么?
webpack是一个javascript应用程序的静态模块化打包工具,它会从入口模块出发,识别出源码中的模块化导入语句,递归地找出入口文件的所有依赖,构建一个依赖关系图。然后将这些模块打包成一个或多个bundle。 - webpack安装
- 全局安装 不推荐
ps:全局安装webpack,这会将项目的webpack锁定到指定版本,如果有项目并不是这个webpack版本,会导致构建失败。# 安装webpack V4+版本时,需要额外安装webp npm install webpack webpack-cli -g- 项⽬安装 推荐
实现了在不同项目中可以安装不同版本的webpack。npm install webpack webpack-cli -D npm i -D webpack@<version>- 检查安装
#command not found 默认在全局环境中查找 webpack -v # npx帮助我们在项⽬中的node_modules⾥查找webpack #./node_modules/.bin/webpack -v//到当前的node_modules模块⾥指定 npx webpack -v webpack - webpack默认配置
webpack默认⽀持JS模块和JSON模块,⽀持CommonJS Es moudule AMD等模块类型,webpack4⽀持零配置使⽤,但是很弱,稍微复杂些的场景都需要额外扩 展。
webpack有默认的配置⽂件,叫webpack.config.js,我们可以对这个⽂件进⾏修改,进⾏个性化配置。不使⽤⾃定义配置⽂件: ⽐如webpackconfig.js,可以通过--config webpackconfig.js来指定webpack使⽤哪个配置⽂件来执⾏构建。
const path = require("path");
module.exports = {
// 必填 webpack执⾏构建⼊⼝
entry: "./src/index.js",
output: {
// 将所有依赖的模块合并输出到main.js
filename: "main.js",
// 输出⽂件的存放路径,必须是绝对路径
path: path.resolve(__dirname, "./dist"),
//在生产环境有效,打包过的静态资源都会加上这个前缀
publicPath:'https://cdn.com/'
}
};
- 执行webpack
# npx⽅式
npx webpack
# npm script
npm run test
#修改package.json⽂件:
"scripts": {
"build": "webpack --config webpack.dev.config.js"
}
二、webpack核心
2.1 entry和output基础配置
- entry
Webpack 执⾏构建的第⼀步将从 Entry 开始。
//单⼊⼝ SPA,本质是个字符串 entry:{ main: './src/index.js' } ==相当于简写=== entry:"./src/index.js" //多⼊⼝ entry是个对象 entry:{ index:"./src/index.js", login:"./src/login.js" } - output
打包转换后的⽂件输出到磁盘位置:输出结果,在 Webpack 经过⼀系列处理 并得出最终想要的代码后输出结果。filename表示输出文件的名称,而输出⽂件到磁盘的⽬录,必须是绝对路径。output: { filename: "bundle.js", path: path.resolve(__dirname, "dist") }, //多⼊⼝的处理 output: { filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重 复 path: path.resolve(__dirname, "dist") },
2.2 mode
通过选择 development 或 production 之中的一个,来设置 mode 参数。设置mode可以⾃动触发webpack内置的函数,达到优化的效果。
2.3 module
在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。Webpack 会 从配置的 Entry 开始递归找出所有依赖的模块。当webpack处理到不认识的模块时,需要在webpack中的module处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处理。
2.4 loader
用于对模块的源代码进行转换。webpack是模块打包工具,但是只支持js和json模块。对其他格式的处理需要loader。
- 样式相关loader
Style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的header部分。npm install style-loader css-loader -Dless-loader 把less语法转换成css,loader有顺序,从右到左,从下到上。module:{ rules:[ { test:/\.css$/, use:[{ loader:"style-loader", options:{ // 将所有的style标签合并成⼀个 injectType:"singletonStyleTag"} },"css-loader" ] } } }$ npm install less less-loader --save-dev样式添加前缀{ test: /\.scss$/, use: ["style-loader", "css-loader", "less-loader"] }npm i postcss-loader autoprefixer -D//webpack.config.js { test: /\.css$/, use:[ "style-loader", { loader:"css-loader", options:{ //js或者css中通过import导入的css,保证解析css的loader,从右边第1个依次解析。 importLoaders:1 } }, "postcss-loader" ] }, //新建postcss.config.js module.exports = { plugins: [ require("autoprefixer")({ overrideBrowserslist: ["last 2 versions", ">1%"] }) ] } - 加载图片
npm install file-loader -D{ test:/\.(png|jpg|gif)$/, use:[{ loader:"file-loader", options:{ name:"[name]_[hash].[ext]", outputPath:"images/" } }] }
url-loader内部使用了file-loader。区别是它解析jpg时,会转换为base64格式,对小体积的图片比较合适,对体积大的图片并不合适,选项可以设置limit,体积小于这个数值,则会转换为base64。npm install url-loader -D{ test:/\.(png|jpg|gif)$/, use:[{ loader:"url-loader", options:{ name:"[name]_[hash].[ext]", outputPath:"images/", <!--单位 byte--> limit:1024 } }] } - 加载字体
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] }
2.5 Plugins
plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,类似于⽣
命周期的概念,作用于整个构建过程。
扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改变构建结
果或做你想要的事情。
- 管理输出
htmlwebpackplugin会在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣ 成的js模块引⼊到该html中。仓库地址:github.com/jantimon/ht…。clean-webpack-plugin用于每次构建前清理/dist文件夹。
npm install --save-dev html-webpack-plugin
npm install --save-dev clean-webpack-plugin
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title:"webpack-train",
filename:"index.html",
//原来的html文件地址
template:"./index.html",
inject:true
})
]
2.6 source map
将编译后的代码映射回原始源代码,为了更容易地追踪错误和警告。devtool这个选项控制是否生成,以及如何生成 source map。
source-map生成.map⽂件;inline:将.map作为dataURI嵌入到输出文件中。cheap:报错代码定位到行,它没有生成列映射;eval:速度最快,会忽略源自loader的source map;Module:源自 loader 的 source map 会得到更好的处理结果。
配置推荐:
devtool:"cheap-module-eval-source-map",// 开发环境配置
devtool:"none" //none或者source-map适用于生产环境
2.7 WebpackDevServer
每次要编译代码时,手动运行 npm run build 就会变得很麻烦。webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:webpack's Watch Mode。
启动服务后,会发现dist⽬录没有了,这是因为devServer把打包后的模块不
会放在dist⽬录下,⽽是放到内存中,从⽽提升速度
、webpack-dev-server、webpack-dev-middleware。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"build": "webpack"
}
webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载。 配置:
# package.json
"scripts": {
"server": "webpack-dev-server"
}
contentBase配置html所在路径,publicPath配置在浏览器访问的路径,默认为:'/'。
devServer:{
port:"8080",
open: true,
hot:true,
contentBase:'./index.html',
//访问路径变成:http://localhost:8080/assets/
publicPath:'/assets/'
}
2.8 热模块替换
模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。
- HMR 修改样式表
借助于 style-loader 的帮助,CSS 的模块热替换实际上是相当简单的。当更新 CSS 依赖模块时,此 loader 在后台使用 module.hot.accept 来修补(patch) style 标签。因此需要配置style-loader、css-loader。启动HMR后,样式修改,页面也会随之更改,且不会刷新页面。
注意启动HMR后,css抽离会不⽣效,还有不⽀持contenthash,chunkhash。 hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
//热模块替换是webpack内置插件
const webpack = require("webpack");
//webpack-server配置
devServer: {
contentBase: "./dist",
open: true,
hot:true,
//即便HMR不⽣效,浏览器也不⾃动刷新,就开启hotOnly
hotOnly:true
}
//插件配置处
plugins: [
new webpack.HotModuleReplacementPlugin()
]
- 处理js模块HMR 。 如果已经通过HMR启用了模块热替换,则它的接口将被暴露在module.hot属性下面。通常,用户先要检查这个接口是否可访问,然后再开始使用它。接受(accept)给定依赖模块的更新,并触发一个 回调函数 来对这些更新做出响应。
if (module.hot) {
module.hot.accept('./number.js', function() {
number();
})
}
2.9 Babel处理ES6
babel-loader只是webpack与babel的通信桥梁,因此需要借助@babel/preset-env将es6转换为js;@babel/preset-env⾥包含了es,6,7,8转es5的转换规则。 babel地址:www.babeljs.cn/docs/babel-…。
npm i babel-loader @babel/core @babel/preset-env -D
{
test:/\.js$/,
exclude:/node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
默认的Babel只⽀持let等⼀些基础的特性转换, Promise等⼀些还有转换过来,这时候需要借助@babel/polyfill,以查找目标环境中缺少的功能,并且仅包括所需的polyfill。www.babeljs.cn/docs/usage#…
npm install --save @babel/polyfill
rc结尾的文件通常代表运行时自动加载的文件,配置等等,.babelrc文件需要的配置项主要有预设(presets)和插件(plugins)。
#业务代码打包场景
//新建.babelrc文件
{"presets": [
[
"@babel/env",
{
//兼容的浏览器设置
"targets": "> 0.2%, not dead",
//按需注入,使用了usage,会自动引入import "@babel/polyfill",
//无需在js中引入
"useBuiltIns": "usage",
}
]
]
}
当我们开发的是组件库,⼯具库这些场景的时候,polyfill就不适合了,因 为polyfill是注⼊到全局变量,window下的,会污染全局环境,所以推荐闭 包⽅式:@babel/plugin-transform-runtime,它不会造成全局污染。www.babeljs.cn/docs/babel-…
npm install --save-dev @babel/plugin-transform-runtime
# core.js为2;npm install --save @babel/runtime-corejs2
npm install --save @babel/runtime
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
#corejs: 2仅支持全局变量(例如Promise)和静态属性(例如Array.from)
"corejs": 2,
"version": "^7.7.4"
}
]
]
}