webpack 基础一
1.webpack开篇
<body>
<!--
1.什么是webpack?
webpack是一套基于NodeJS的"模块打包工具",
在webpack刚推出的时候就是一个单纯的JS模块打包工具,可以将多个模块的JS文件合并打包到一个文件中
但是随着时间的推移、众多开发者的追捧和众多开发者的贡献
现在webpack不仅仅能够打包JS模块, 还可以打包CSS/LESS/SCSS/图片等其它文件
2.为什么要分模块?
如果将所有的JS代码都写到一个文件中, 十分不利于代码的维护和复用
所以我们可以将不同的功能写到不同的模块中, 这样就提升了代码的维护性和复用性
但是当将代码写到不同模块时新的问题又出现了,
例如: 导入资源变多了, 请求次数变多了, 网页性能也就差了
例如: 不同功能都放到了不同模块中了, 那么如何维护模块之间的关系也变成一个难题了
<script src="./header.js"></script>
<script src="./content.js"></script>
<script src="./index.js"></script>
<script src="./footer.js"></script> // 如果index.js中用到了footer,就会报错,因为顺序执行的原因
例如: ... ...
3.如何解决上述问题
3.1 将上述js文件封装成模块,在主文件中再导入依赖模块
3.2项目上线时将用到的所有模块都合并到一个文件中,通过webpack打包
3.3在index.html中只导入主文件
4.如何通过webpack来打包JS模块
4.1安装webpack
npm init -y
npm install --save-dev webpack
npm install --save-dev webpack-cli
4.2在终端中输入打包的指令
npx webpack index.js
注意点:
index.js就是需要打包的文件
打包之后的文件会放到dist目录中, 名称叫做main.js
-->
<!--如下,我把header ,content,footer放在index里,然后打包index代码就可以了
<script src="index.js"></script>
<script src="Header.js"></script>
<script src="Content.js"></script>
<script src="Footer.js"></script>
-->
<script src="dist/main.js"></script>
</body>
2.webpack配置文件
2.1
<body>
<!--
1.什么是webpack配置文件?
我们在打包JS文件的时候需要输入: npx webpack index.js
这句指令的含义是: 利用webpack将index.js和它依赖的模块打包到一个文件中
其实在webpack指令中除了可以通过命令行的方式告诉webpack需要打包哪个文件以外,
还可以通过配置文件的方式告诉webpack需要打包哪个文件
2.webpack常见配置
entry: 需要打包的文件
output: 打包之后输出路径和文件名称
mode: 打包模式 development/production
development: 不会压缩打包后的JS代码
production: 会自动压缩打包后的JS代码
-->
<!--<script src="dist/main.js"></script>-->
<script src="bundle/bundle.js"></script>
</body>
js代码如下
const path = require("path");
module.exports = {
/*
mode: 指定打包的模式, 模式有两种
一种是开发模式(development): 不会对打包的JS代码进行压缩
还有一种就是上线(生产)模式(production): 会对打包的JS代码进行压缩
* */
mode: "development", // "production" | "development"
/*
entry: 指定需要打包的文件
* */
entry: "./index.js",
/*
output: 指定打包之后的文件输出的路径和输出的文件名称
* */
output: {
/*
filename: 指定打包之后的JS文件的名称
* */
filename: "bundle.js",
/*
path: 指定打包之后的文件存储到什么地方
* */
path: path.resolve(__dirname, "bundle")
}
};
2.2 配置文件注意点
<body>
<!--
1.webpack配置注意事项
配置文件的名称必须叫做: webpack.config.js, 否则直接输入 npx webpack打包会出错
如果要使用其它名称, 那么在输入打包命令时候必须通过 --config 指定配置文件名称
npx webpack --config xxx
2.打包命令简化
每次输入npx webpack --config xxx来打包文件会有一点蛋疼, 所以我们可以通过npm script来简化这个操作
即在初始化npm后在package.json改为如下
"scripts": {
"test": "npx webpack --config webpack.config.js"
},
-->
<script src="bundle/bundle.js"></script>
</body>
3.sourcemap
<body>
<!--
1.什么是sourcemap?
webpack打包后的文件会自动添加很多代码, 在开发过程中非常不利于我们去调试
因为如果运行webpack打包后的代码,错误提示的内容也是打包后文件的内容
所以为了降低调试的难度, 提高错误代码的阅读性, 我们就需要知道打包后代码和打包之前代码的映射关系
只要有了这个映射关系我们就能很好的显示错误提示的内容, 存储这个映射关系的文件我们就称之为sourcemap
2.如何开启sourcemap
https://www.webpackjs.com/configuration/devtool/
2.1在webpack.config.js中添加
devtool: "xxx",
2.2各配置项说明:
eval:
不会单独生成sourcemap文件, 会将映射关系存储到打包的文件中, 并且通过eval存储
优势: 性能最好
缺点: 业务逻辑比较复杂时候提示信息可能不全面不正确
source-map:
会单独生成sourcemap文件, 通过单独文件来存储映射关系
优势: 提示信息全面,可以直接定位到错误代码的行和列
缺点: 打包速度慢
inline:
不会单独生成sourcemap文件, 会将映射关系存储到打包的文件中, 并且通过base64字符串形式存储
cheap:
生成的映射信息只能定位到错误行不能定位到错误列
module:
不仅希望存储我们代码的映射关系, 还希望存储第三方模块映射关系, 以便于第三方模块出错时也能更好的排错
了解后我们只需要以下用就行
2.3企业开发配置:
development: cheap-module-eval-source-map
只需要行错误信息, 并且包含第三方模块错误信息, 并且不会生成单独sourcemap文件
production: cheap-module-source-map
只需要行错误信息, 并且包含第三方模块错误信息, 并且会生成单独sourcemap文件
-->
<script src="bundle/bundle.js"></script>
</body>
js代码
//在上面配置文件的基础上加上以下配置即可
/*
配置sourcemap
development: cheap-module-eval-source-map
production: cheap-module-source-map
* */
devtool: "cheap-module-source-map",
4.接下来要学习各种各样的loader
4.1 loader基本概念
<body>
<!--
1.什么是loader?
webapck的本质是一个模块打包工具, 所以webpack默认只能处理JS文件,不能处理其他文件,
因为其他文件中没有模块的概念, 但是在企业开发中我们除了需要对JS进行打包以外,
还有可能需要对图片/CSS等进行打包, 所以为了能够让webpack能够对其它的文件类型进行打包,
在打包之前就必须将其它类型文件转换为webpack能够识别处理的模块,
用于将其它类型文件转换为webpack能够识别处理模块的工具我们就称之为loader
2.如何使用loader
webpack中的loader都是用NodeJS编写的, 但是在企业开发中我们完全没有必要自己编写,
因为已经有众多大神帮我们编写好了企业中常用的loader, 我们只需要安装、配置、使用即可
2.1通过npm安装对应的loader
2.2按照loader作者的要求在webpack进行相关配置
2.3使用配置好的loader
-->
</body>
4.2 fileloader使用
<!--
fileloader使用
https://www.webpackjs.com/loaders/file-loader/
1.1安装file-loader
npm install --save-dev file-loader
1.2在webpack.config.js中配置file-loader
module: 告诉webpack如何处理webpack不能够识别的文件
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
}
-->
</body>
4.3 loader其他配置
<body>
<!--
注意点:
默认情况下fileloader生成的图片名就是文件内容的 MD5 哈希值
如何想打包后不修改图片的名称, 那么可以新增配置 name: "[name].[ext]"
其它命名规则详见: placeholders
注意点:
默认情况下fileloader会将生成的图片放到dist根目录下面
如果想打包之后放到指定目录下面, 那么可以新增配置 outputPath: "images/"
注意点:
如果需要将图片托管到其它服务器, 那么只需在打包之前配置 publicPath: "托管服务器地址"即可
-->
</body>
js代码如下
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
// 指定打包后文件名称
name: '[name].[ext]',
// 指定打包后文件存放目录
outputPath: 'images/',
// 指定托管服务器地址(统一替换图片地址)
publicPath: 'http://www.it666.com/images/'
}
}
]
}
]
}
4.4 url-loader的使用
<body>
<!--
1.urlloader
url-loader 功能类似于 file-loader,
但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL
2.urlloader使用
https://www.webpackjs.com/loaders/url-loader/
2.1安装urlloader
npm install --save-dev url-loader
2.2配置urlloader
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
/*
limit: 指定图片限制的大小
如果被打包的图片超过了限制的大小, 就会将图片保存为一个文件
如果被打包的图片没有超过限制的大小, 就会将图片转换成base64的字符串
注意点:
对于比较小的图片, 我们将图片转换成base64的字符串之后, 可以提升网页的性能 (因为减少了请求的次数)
对于比较大的图片, 哪怕我们将图片转换成了base64的字符串之后, 也不会提升网 页的性能, 还有可能降低网页的性能
(因为图片如果比较大, 那么转换之后的字符串也会比较多, 那么网页的体积就会比较 大, 那么访问的速度就会变慢)
*/
limit: 1024 * 100,
// 指定打包后文件名称
name: '[name].[ext]',
// 指定打包后文件存放目录
outputPath: 'images/',
}
}
]
}
优势:
图片比较小的时候直接转换成base64字符串图片, 减少请求次数
图片比较大的时候由于生成的base64字符串图片也比较大, 就保持原有的图片
-->
</body>
4.5 css-loader的使用
<body>
<!--
1.css-loader
和图片一样webpack默认能不能处理CSS文件, 所以也需要借助loader将CSS文件转换为webpack能够处理的类型
2.css-loader使用:
2.1安装cssloader
npm install --save-dev css-loader
2.2安装styleloader
npm install style-loader --save-dev
2.3配置css-loader
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
3.css-loader和style-loader作用
css-loader: 解析css文件中的@import依赖关系
style-loader: 将webpack处理之后的内容插入到HTML的HEAD代码中
注意点:
4.loader特点:
4.1单一原则, 一个loader只做一件事情
4.2多个loader会按照从右至左, 从下至上的顺序执行
例如: 从右至左
[ 'style-loader', 'css-loader' ]
先执行css-loader解析css文件关系拿到所有内容,
再执行style-loader将内容插入到HTML的HEAD代码中
例如: 从下至上
[{
loader: "style-loader"
},{
loader: "css-loader"
}]
先执行css-loader解析css文件关系拿到所有内容,
再执行style-loader将内容插入到HTML的HEAD代码中
-->
</body>
4.6 ES6-Module
<body>
<!--
1.ES6模块化
在ES6出现之前,JS不像其他语言拥有“模块化”这一概念,于是为了支持JS模块化
我们使用类、立即执行函数或者第三方插件(RequireJS、seaJS)来实现模块化
但是在ES6出现之后, 上述解决方案都已经被废弃, 因为ES6中正式引入了模块化的概念
ES6模块化模块和NodeJS中一样, 一个文件就是一个模块, 模块中的数据都是私有的
ES6模块化模块和NodeJS中一样, 可以通过对应的关键字暴露模块中的数据,
可以通过对应的关键字导入模块, 使用模块中暴露的数据
2.ES6模块化使用
2.1常规导出
2.1.1分开导入导出
export xxx;
import {xxx} from "path";
2.1.2一次性导入导出
export {xxx, yyy, zzz};
import {xxx, yyy, zzz} from "path";
注意点:
接收导入变量名必须和导出变量名一致
如果想修改接收变量名可以通过 xxx as newName方式
变量名被修改后原有变量名自动失效
2.2默认导入导出
export default xxx;
import xxx from "path";
注意点:
一个模块只能使用一次默认导出, 多次无效
默认导出时, 导入的名称可以和导出的名称不一致
-->
<script src="index.js"></script>
</body>
来用js写一下
/*
ES6模块化的第一种方式
导出数据: export {xxx};
导入数据: import {xxx} from "path";
*/
/*
注意点:
1.如果是通过export {xxx};方式导出数据, 那么在导入接收的时候接收的变量名称必须和导出的名称一致
究其原因是因为在导入的时候本质上是ES6的解构赋值
2.如果是通过export {xxx};方式导出数据, 又想在导入数据的时候修改接收的变量名称, 那么可以使用as来修改
但是如果通过as修改了接收的变量名称, 那么原有的变量名称就会失效
*/
import {name} from "./a.js";//a.js中定义name
/*
下为解构赋值
let obj = {
name: "lnj",
age: 34
};
let {name, age} = obj;
console.log(name);
let {str, age} = obj; str是undefined
console.log(str);
console.log(age);
*/
//下为注意点2
import {name as str} from "./a.js";
console.log(name);//此时name啥也没了
console.log(str);
/*
ES6模块化的第二种方式
导出数据: export default xxx;
导入数据: import xxx from "path";
*/
/*
注意点:
1.如果是通过export default xxx;导出数据, 那么在接收导出数据的时候变量名称可以和导出的名字不一致
2.如果是通过export default xxx;导出数据, 那么在模块中只能使用一次export default
*/
// import name from "./b.js";此时两种方式都正确
import str from "./b.js";
console.log(str);
//此时下面使用了两次导出的操作,所以会报错
import name from "./b.js";
import age from "./b.js";
console.log(name);
console.log(age);
// 两种方式混合使用
import Person,{name, age, say} from "./c.js"; //c中定义了三个变量和一个Person类,采用不同的导出方式
let p = new Person();
console.log(p);
console.log(name);
console.log(age);
say();
//学习了es6的导入导出后,我们以前使用的require导入就可以换一种写法
// const icon = require("./lnj.jpg");
// const _ = require("./index.css");
import icon from "./lnj.jpg";
import "./index.css";
let oImg = document.createElement("img");
oImg.src = icon;
oImg.setAttribute("class", "size");//index.css中对图片进行了一些操作
document.body.appendChild(oImg);
4.7 less-loader
<body>
<!--
1.less-loader
自动将less转换为CSS
2.less-loader使用:
2.0安装less
npm install --save-dev less
2.1安装less-loader
npm install --save-dev less-loader
2.2配置less-loader
在rules中添加以下代码
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
}
注意点:
因为loader是从右至左从下至上,所以必须先由less-loader处理往后才能交给其他loader处理
-->
</body>
4.8 sass-loader
<body>
<!--
1.scss-loader
自动将scss转换为CSS
2.scss-loader使用:
2.0安装scss
npm install --save-dev node-sass
2.1安装less-loader
npm install --save-dev sass-loader
2.2配置less-loader
{
test: /\.scss$/,
use: [{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Sass 编译成 CSS
}]
}
注意点:
因为loader是从右至左从下至上,所以必须先由sass-loader处理往后才能交给其他loader处理
-->
</body>
4.9 PostCSS-loader之补全前缀(棒呆了)
<body>
<!--
1.什么是PostCSS?
https://www.postcss.com.cn/
PostCSS和sass/less不同, 它不是CSS预处理器
PostCSS是一款使用插件去转换CSS的工具,
PostCSS有许多非常好用的插件
例如
autoprefixer(自动补全浏览器前缀)
postcss-pxtorem(自动把px代为转换成rem)
... ...
-->
<!--
2.使用PostCSS自动补全浏览器前缀
2.1安装postcss-loader
npm i -D postcss-loader
2.2安装需要的插件
npm i -D autoprefixer
2.3配置postcss-loader
在css-loader or less-loader or sass-loader之前添加postcss-loader
2.4创建postcss-loader配置文件(新加的一步)
postcss.config.js
https://github.com/browserslist/browserslist#queries
2.5在postcss.config.js配置文件中配置autoprefixer
module.exports = {
plugins: {
"autoprefixer": {
"overrideBrowserslist": [
// "ie >= 8", // 兼容IE7以上浏览器
// "Firefox >= 3.5", // 兼容火狐版本号大于3.5浏览器
// "chrome >= 35", // 兼容谷歌版本号大于35浏览器,
// "opera >= 11.5" // 兼容欧朋版本号大于11.5浏览器,
"chrome >= 36", // 如果需要适配的浏览器完全兼容则不会添加前缀
]
}
}
};
-->
</body>
4.10 PostCSS-loader之转换px为rem(棒呆了)
在前边的项目中,为了适配屏幕,学习了许多适配方法,最常用的有通过rem适配,我们先通过图片大小以及屏幕大小计算根目录的fontsize(计算方法在前面的笔记),然后使用的时候我们需要这样来写,比如高度是300px,我们得写300/100rem(举个例子),现在有了PostCSS-loader就不用这么麻烦了.
<body>
<!--
3.使用PostCSS自动将px转换成rem
https://www.npmjs.com/package/postcss-pxtorem
3.1安装postcss-pxtorem
npm install postcss-pxtorem -D
3.2在postcss.config.js配置文件中配置postcss-pxtorem
"postcss-pxtorem": {
rootValue: 100, // 就是我们上面要除的那个100,也就是原始图片每一份的大小
// propList: ['*'] // 可以从px更改到rem的属性
propList: ["height"]
}
rootValue (Number) root 元素的字体大小。
unitPrecision (Number) 允许REM单位增长到的十进制数。
propList ( array ) 可以从px更改到rem的属性。
值需要精确匹配。
使用通配符 * 启用所有属性。 示例:['*']
在单词的开头或者结尾使用 *。 ( ['*position*'] 将匹配 background-position-y )
使用 与属性不匹配。! 示例:['*','letter-spacing']!
将"非"前缀与其他前缀合并。 示例:['*','font*']!
selectorBlackList ( array ) 要忽略和离开的选择器。
如果值为字符串,它将检查选择器是否包含字符串。
['body'] 将匹配 .body-class
如果值为 regexp,它将检查选择器是否匹配正则表达式。
[/^body$/] 将匹配 body,但不匹配 .body
replace (Boolean) 替代包含rems的规则,而不是添加回退。
mediaQuery (Boolean) 允许在媒体查询中转换 px。
minPixelValue (Number) 设置要替换的最小像素值。
突然感觉淡淡不忧伤了, 过去麻烦的事webpack都帮我们做完了
-->
</body>
4.11 css-loader 模块化
<body>
<!--
1.默认情况下通过import "./xxx.css"导入的样式是全局样式
也就是只要被导入, 在其它文件中也可以使用
如果想要导入的CSS文件只在导入的文件中有效, 那么就需要开启CSS模块化
{
loader: "css-loader",
options: {
modules: true // 开启CSS模块化
}
}
然后在导入的地方通过 import xxx from "./xxx.css"导入
然后在使用的地方通过 xxx.className方式使用即可
-->
</body>
举个例子
import icon from "./lnj.jpg";
// import "./index.css"
import cssModule from "./index.css"//导入方式改变
import {addImage} from "./custom.js";
console.log(cssModule);
let oImg = document.createElement("img");
oImg.src = icon;
// oImg.setAttribute("class", "size");
oImg.setAttribute("class", cssModule.size);//使用方式改变
document.body.appendChild(oImg);
addImage();//这里是另一个js文件,如下
//本来在没有模块化时, less文件中的size类会对两张图片作用,而模块化后,只对当前文件的图片产生作用
/*
import icon from "./lnj.jpg";
function addImage() {
let oImg = document.createElement("img");
oImg.src = icon;
oImg.setAttribute("class", "size");
document.body.appendChild(oImg);
}
export {addImage};
*/
4.12 iconfont-loader使用
<body>
<!--
1.如何打包字体图标
字体图标中也用到了url用到了文件, 所以我们需要通过file-loader来处理字体图标文件
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use:[{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "font/",
}
}]
}
-->
</body>
在js使用时
import "./font/iconfont.css"
document.body.innerHTML = "<i class='iconfont icon-icon' style='font-size: 100px'></i>";