前端云原生学习笔记
文章目录
一、前端工程化基础
1、node与npm
-
node版本建议10以上,用
node -v
查看版本,npm -v
查看npm的版本,现在的node安装的时候会自动装npm -
装好之后默认的获取地址是淘宝,需要修改
C:\Users\Dell>npm config get registry https://registry.npm.taobao.org/ C:\Users\Dell>npm config set registry https://registry.npmmirror.com/ C:\Users\Dell>npm config get registry https://registry.npmmirror.com/
2、命令行常见指令
# 切换目录
cd [directory]
# 跳至上级目录
cd ..
# 查看当前目录
# windows cmd对应的命令是echo %cd%
pwd
# 查看当前目录下所有文件
# windows cmd对应的命令是dir
ls
ls -a
# 创建目录
mkdir [directoryName]
# 删除目录
rmdir [directoryName]
# 创建文件
# windows cmd对应的命令是echo [fileContent]>[fileName]
touch [fileName]
# 创建了src.txt文件
touch src.txt
# 复制文件
# windows cmd对应的命令是copy
cp
# 创建了src.txt的副本src.txt.bak
cp src.txt src.txt.bak
# 删除文件
# windows cmd对应的命令是del
rm [fileName]
# 示例 : 删除src.txt文件
rm src.txt
# 查看文件内容
# windows cmd对应的命令是type
cat [fileName]
# 示例 : 查看src.txt文件内容
cat src.txt
注意:
列出的这些基础指令 mac 也能用,
windows cmd
有些命令不同,在注释中有标出;
还有一些常见的指令没有列出,感兴趣的自行拓展;
在本文档中用到的npm
相关指令,是在三个操作系统的命令行中都能通用的.
3、初始化项目与babel转译
-
选择路径,新建项目文件夹,并进入该文件夹
cd 路径 mkdir filename cd filename
-
初始化项目
npm init
然后一路回车,
description
和author
想写就写一点,结束之后会生成一个package.json
文件 -
编写配置文件
babel.config.json
,将babel
预设写入配置文件Babel 提供了预设(
preset
),预设是将需要的插件进行组合,组合好的一个预设,就能够一次性转换项目里用到的所有 ES6 特性。Babel 官方按照
ECMAScript
草案,已经针对常用环境编写了一些预设:- @babel/preset-env for compiling ES2015+ syntax // 一般情况下,这个预设就够用了 - @babel/preset-typescript for TypeScript // 适用于Typescript - @babel/preset-react for React // 适用于react - @babel/preset-flow for Flow // 适用于flow
和插件一样,
preset
也是可以写入babel.config.json
配置文件中的。在终端命令行执行,创建
babel.config.json
文件,并在vsCode
:中打开编辑:code babel.config.json
在
babel.config.json
配置文件中写入:{ "presets": ["@babel/preset-env"] }
然后保存
也可以用插件,将用到的插件以数组的形式写入
babel.config.json
配置文件中:{ "plugins": [ "@babel/plugin-transform-exponentiation-operator", "@babel/plugin-transform-arrow-functions", "@babel/plugin-transform-block-scoping" ] }
知道插件地址就行,不过有一点点麻烦
-
在终端命令行执行,创建
src.js
文件,并在vsCode
中打开编辑:code src.js
在
src.js
中写入所需ES6
代码 -
打开package.json文件,添加实时监控
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "babel-watch": "babel src.js --watch --out-file dist.js" },
-
保存
babel/core
,否则后面run
会报错"找不到babel/core
"npm install --save-dev @babel/core
-
在终端执行,监控
src.js
代码变化,并实时转译npm run babel-watch # ctrl+c 可以退出watch监控 终止批处理操作吗(Y/N)? y
至此,即达到实时编写转译。
4、Sass——CSS预处理器
-
安装Sass
# npm全局安装sass, 这样在其他项目里,也能直接调用,不需要重新安装 npm install -g sass # 查看版本,确定安装成功 sass --version > 1.44.0 compiled with dart2js 2.14.4
-
初始化样式
# 安装reset-css npm install --save reset-css
然后在
src/main.scss
引入reset css
,进行样式的初始化,同时设置box-sizing
为border-box
:// 在main.scss中使用 @use 引入reset-css @use "../../node_modules/reset-css/sass/reset"; // 使用border-box * { box-sizing: border-box; }
保存
main.scss
,在项目根目录下,运行sass
的编译指令:sass ./src/css/main.scss ./src/css/main.css
可以看到,
src/css
目录下,多出了main.css
和main.css.map
两个文件,main.css
大家很熟悉,main.css.map
是 SourceMap 文件。- 我们查看下
main.css
,可以发现 reset 样式已经写入其中; - 在浏览器中打开
index.html
文件,可以看到reset-css
已经生效。
- 我们查看下
-
watch
监控变化,实时转译package.json
文件中写入:"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "sass-watch": "sass --watch ./src/css/main.scss ./src/css/main.css" },
在终端控制台运行指令,开启实时监控:
# 运行指令 npm run sass-watch # 控制台输出 > c_auth@1.0.0 sass-watch > sass --watch ./src/css/main.scss ./src/css/main.css Sass is watching for changes. Press Ctrl-C to stop.
之后即可保持
watch
状态往下编写代码。
5、编写样式
-
嵌套
可以让样式的书写能直接对应上
html
元素的层级,编写和维护都更加清晰。 -
变量
将主题颜色拎出来赋值给
themeColor
,后期更改主题颜色只需更改此处赋值即可。使用变量:
// 语法是"$+变量名" // 定义了themeColor变量 $themeColor: #ff5100; .app-container { // ... 省略了header部分 // banner-container未变的部分,也未贴出 .banner-container { background-color: #242345; border-top: 2px solid $themeColor; // ... .banner-buttons { .tutor { background-color: $themeColor; } } } }
-
mixin
便于复用代码。
// 定义mixin ; 绝对定位 @mixin absolutePosition($top, $right) { position: absolute; top: $top; right: $right; } i { display: inline-block; width: 11.2rem; height: 19.6rem; z-index: 2; // 使用absolutePosition @include absolutePosition(-3.2rem, 0); background: url("../img/sj@3x.png") no-repeat; background-size: cover; }
-
继承
注意:不可以跳父级继承,只能继承同一个爸爸的样式属性!
继承了之后,补上不同的地方要写的代码即可。
.order { /* 属性继承 */ @extend .tutor; background-color: #e8e8e8; color: #111111; float: right; }
-
模块
在使用原生 css 时,我们就知道,不需要把页面的所有样式都写在一个 css 文件里,可以按布局或者功能分割成几个不同的 css 文件,在 html 分别引入即可; 这样既可以复用,也方便维护;
Sass 的模块就是基于这样的思想,可以在主 scss 文件里,通过@use
来引入其他模块文件中的变量和 mixin 等;
比如,我们在src/css
目录下,新建一个base.scss
文件,把之前在main.scss
里定义的变量和初始化样式等,放到base.scss
里去。// 把变量和@mixin, header样式等抽离; 模块化引入 @use "base"; // 创建一个 base 命名空间 h1 { @include base.fontSet(2.4rem, 600); border-top: 2px solid base.$themeColor; }
随着项目复杂度的增加,把样式文件分割成几个 scss 文件,比如分成基础全局样式、特定布局样式、全局变量值等,更便于开发和维护。
-
注释
scss 文件中的注释有如下两种:
- 标准的 CSS 注释
/* comment */
,会保留到编译后的文件 - 单行注释
// comment
,只保留在 scss 文件中,编译到 css 文件后,会被省略 - 重要注释:在/*后面加一个感叹号,表示这是"重要注释"。即使是压缩模式编译,也会保留这行注释
/*! 这是重要注释! */
- 标准的 CSS 注释
-
计算
在 scss 样式文件里,我们可以直接进行某些样式值的计算:
@use "sass:math"; // 引入sass内置的math模块 width: math.div(600, 960) * 100%;
还原设计稿的时候,有些计算起来比较麻烦的值,就不用自己先计算出来了。
-
其他 Sass 特性
Sass 还有很多其他的功能,包括丰富的内置函数(颜色函数等)、允许用户自定义函数等,感兴趣的自己拓展.
6、Babel 与 Sass 组合使用
-
增加 JS 动效
js代码如下:
window.addEventListener("load", swipeSponsor); function swipeSponsor() { const sponsorList = document.querySelector(".sponsor-wrapper"); // 轮换区 const indicators = document.querySelectorAll(".swipe-container a"); // 指示器 const swipeTotal = 5; // 图片轮换数 const sponsor = document.querySelector(".sponsor"); const perWidth = sponsor.clientWidth; // 轮换显示区,占宽,像素值; sponsorList.style.left = -perWidth + "px"; // 初始化sponsorList的左侧坐标 const indicatorTotal = indicators.length; // 指示器数量 let disX = 0; // 滑动时,触点相对于html左边缘的x坐标 let disL = 0; // .sponsor-wrapper的left值 let disGap = 0; // 滑动时,pageX的差值 let indicatorIndex = 0; // 给当前指示器添加active类 // touchstart sponsorList.addEventListener("touchstart", (event) => { event.preventDefault(); disGap = 0; disX = event.changedTouches[0].pageX; // pageX:触点相对于HTML文档左边缘的X坐标 disL = sponsorList.offsetLeft; // offsetLeft : 当前元素左上角相对HTMLElement.offsetParent节点的左边界偏移的像素值。 sponsorList.style.transition = null; // 清除过渡 replaceSwipe(); }); // 让sponsorList跟随滑动,变化left值 sponsorList.addEventListener("touchmove", (event) => { event.preventDefault(); // 触点移动距离 disGap = event.changedTouches[0].pageX - disX; sponsorList.style.left = disL + disGap + "px"; }); // 滑动结束时 sponsorList.addEventListener("touchend", (event) => { event.preventDefault(); // 限定disGap不能大于1.5 perWidth if (Math.abs(disGap) > 1.5 * perWidth) { if (disGap > 0) disGap = perWidth; else disGap = -perWidth; } let scale = Math.round(disGap / perWidth); // 四舍五入,判断滑动是否过半 sponsorList.style.left = disL + scale * perWidth + "px"; disL = sponsorList.offsetLeft; // 重新获取sponsorList的left值 replaceSwipe(); // 指示器样式初始化 for (let i = 0; i < indicatorTotal; i++) { indicators[i].classList.remove("active"); } // 根据当前的.sponsor-wrapper的left值,判断该激活哪个指示器 indicatorIndex = Math.abs((disL + perWidth) / perWidth); // 根据index值,给指示器添加类active indicators[indicatorIndex].classList.add("active"); }); // 类似轮播图的无缝衔接 function replaceSwipe() { // 当处于最左边的3图时,切换到倒数第二张3图,无缝切换 if (disL > -perWidth) { disL = -perWidth * indicatorTotal; } else if (disL <= -perWidth * (swipeTotal - 1)) { // 当处于最右边的1图时,切换到第二张1图,无缝切换; disL = -perWidth; } } }
-
构建
dist
目录-
安装
babel preset
npm install -D @babel/preset-env
-
保存
babel/core
,否则后面build
会报错"找不到babel/core
"npm install --save-dev @babel/core
-
在根目录下创建
babel.config.json
文件,指定预设:{ "presets": ["@babel/preset-env"] }
-
在
package.json
里添加build
指令:"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "sass-watch": "sass --watch ./src/css/main.scss ./src/css/main.css", "build": "sass --style=compressed --no-source-map ./src/css/main.scss ./dist/css/main.css && babel ./src/js/main.js --out-file ./dist/js/main.js" },
在新增的
build
里,--style=compressed
参数是压缩编译生成的 css 文件,这样生成的 css 文件体积更小,让页面的加载速度更快; -
运行
build
:npm run build
-
由于没有对
html
和图片进行处理,所以直接将html
和整个img
文件夹复制粘贴去dist目录下即可。
-
7、gulp
它是一个基于流(stream)的自动化构建工具,使用的是 node 中的 stream 来读取和操作数据。
-
安装 gulp
运行下面的指令,全局安装
gulp-cli
,项目本地安装gulp
:# 全局安装gulp命令行工具 npm install -g gulp-cli # 在c_auth根目录下,安装gulp npm install -D gulp # 检查gulp版本 gulp --version # 显示 gulp-cli和gulp版本 >> CLI version: 2.3.0 Local version: 4.0.2
-
使用gulp
-
安装所需 gulp 插件
# del是node原生的删除模块 npm install -D del gulp-autoprefixer gulp-babel gulp-concat gulp-htmlmin gulp-rename gulp-sass sass gulp-sourcemaps gulp-uglify gulp-htmlmin gulp-rename
-
编写 gulpfile.js
gulpfile.js
// 引入API和插件 const { src, dest, watch, series, parallel } = require("gulp"); // 引入用到的gulp API const del = require("del"); // 删除 const htmlMin = require("gulp-htmlmin"); // html压缩 const rename = require("gulp-rename"); // 文件重命名 const concat = require("gulp-concat"); // 文件合成 const sourcemaps = require("gulp-sourcemaps"); // 生成sourcemap const sass = require("gulp-sass")(require("sass")); // sass转css const autoprefixer = require("gulp-autoprefixer"); // css前缀 const babel = require("gulp-babel"); // babel转换 const uglify = require("gulp-uglify"); // JavaScript压缩 function cleanDist() { return del(["dist/js", "dist/css", "dist/index.html"]); // 清除dist下的js,css和html构建文件 } function htmlMini() { return src("src/*.html") .pipe(htmlMin({ collapseWhitespace: true })) // html压缩,去除空白 .pipe(rename("dist.html")) .pipe(dest("dist")); } function cssMini() { return src("src/css/main.scss") .pipe(sourcemaps.init()) // 生成sourcemap,测试环境下需要; 生产环境可移除 .pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError)) // 将scss转成css .pipe(autoprefixer({ browsers: ['last 2 versions'] })) // 添加前缀 .pipe(sourcemaps.write(".")) // 生成sourcemap文件 .pipe(dest("dist/css")); } function jsMini() { return src("src/js/*.js", { base: "src/js" }) .pipe(concat("main.js")) // 将src/js目录下的js文件合并成一个main.js文件 .pipe( babel({ presets: ["@babel/env"], }) ) // babel .pipe(uglify()) // 压缩main.js文件 .pipe(dest("dist/js")); } // 先清空dist目录,再执行源文件处理 exports.default = series(cleanDist, parallel(htmlMini, cssMini, jsMini)); // watch实时监控更改 watch("src/js/*.js", jsMini); watch("src/css/*.scss", cssMini); watch("src/*.html", htmlMini);
-
报错了
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: E:\湖商\求 职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\node_modules\del\index.js require() of ES modules is not supported. require() of E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\node_modules\del\index.js from E:\湖商\求职 \CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules. Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\node_modules\del\package.json. at Object.Module._extensions..js (internal/modules/cjs/loader.js:1089:13) at Module.load (internal/modules/cjs/loader.js:937:32) at Function.Module._load (internal/modules/cjs/loader.js:778:12) at Module.require (internal/modules/cjs/loader.js:961:19) at require (internal/modules/cjs/helpers.js:92:18) at Object.<anonymous> (E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js:3:13) at Module._compile (internal/modules/cjs/loader.js:1072:14) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10) at Module.load (internal/modules/cjs/loader.js:937:32) at Function.Module._load (internal/modules/cjs/loader.js:778:12) { code: 'ERR_REQUIRE_ESM' }
搜索错误代码语句,查找到网页,将引入的代码更改如下:
// 引入API和插件 import { src, dest, watch, series, parallel } from 'gulp'; // 引入用到的gulp API import del from 'del'; // 删除 import htmlMin from "gulp-htmlmin"; // html压缩 import rename from "gulp-rename"; // 文件重命名 import concat from "gulp-concat"; // 文件合成 import sourcemaps from "gulp-sourcemaps"; // 生成sourcemap import sass from "gulp-sass"; // sass转css import autoprefixer from "gulp-autoprefixer"; // css前缀 import babel from "gulp-babel"; // babel转换 import uglify from "gulp-uglify"; // JavaScript压缩
依然报错:
PS E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth> gulp file:///E:/%E6%B9%96%E5%95%86/%E6%B1%82%E8%81%8C/CSDNsuperIntern/gsdx/0704-0710/%E6%9C%B1%E6%96%B9%E8%B6%8A/c4-advanced-01-foundation/c_auth/gulpfile.mjs:3 import del from 'del'; // 删除 ^^^ SyntaxError: The requested module 'del' does not provide an export named 'default' at ModuleJob._instantiate (internal/modules/esm/module_job.js:121:21) at async ModuleJob.run (internal/modules/esm/module_job.js:166:5) at async Loader.import (internal/modules/esm/loader.js:178:24)
搜索错误代码语句,查找到网页,将引入的代码更改如下:
import {del} from 'del'; // 删除
依然报错:
PS E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth> gulp file:///E:/%E6%B9%96%E5%95%86/%E6%B1%82%E8%81%8C/CSDNsuperIntern/gsdx/0704-0710/%E6%9C%B1%E6%96%B9%E8%B6%8A/c4-advanced-01-foundation/c_auth/gulpfile.mjs:3 import {del} from 'del'; // 删除 ^^^ SyntaxError: The requested module 'del' does not provide an export named 'del' at ModuleJob._instantiate (internal/modules/esm/module_job.js:121:21) at async ModuleJob.run (internal/modules/esm/module_job.js:166:5) at async Loader.import (internal/modules/esm/loader.js:178:24)
同伴的电脑没出现这样的问题,她用的node版本是16.15.1,而我的是14.17.5,于是我用nvm下载安装并切换了node版本:
# 下载安装 nvm install 16.15.1 # 查看node版本列表 nvm ls # 必须要管理员权限打开才可以切换成功 nvm use 16.15.1 # 查看node版本 node -v
把代码改回之前的const require、mjs改回js、删掉package.json里的type:module之后,还是报错:
PS E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth> gulp Error [ERR_REQUIRE_ESM]: require() of ES Module E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\node_modules\del\index.js from E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js not supported. Instead change the require of index.js in E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js to a dynamic import() which is available in all CommonJS modules. at Object.<anonymous> (E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js:3:13) at async Promise.all (index 0) { code: 'ERR_REQUIRE_ESM' }
重新安装了一遍gulp之后,再运行gulp,依然是同样的报错。
-
解决办法:
根本矛盾:del版本差异导致,我是7点几,其他没问题的人是6.1.1
# 卸载当前版本的del npm uninstall del # 安装6.1.1版本的del npm insatall del@6.1.1 # 运行一下看能不能成功 gulp # 成功了,显示如下: [23:41:40] Using gulpfile E:\湖商\求职\CSDNsuperIntern\gsdx\0704-0710\朱方越\c4-advanced-01-foundation\c_auth\gulpfile.js [23:41:41] Starting 'default'... [23:41:41] Starting 'cleanDist'... [23:41:41] Finished 'cleanDist' after 101 ms [23:41:41] Starting 'htmlMini'... [23:41:41] Starting 'cssMini'... [23:41:41] Starting 'jsMini'... Replace Autoprefixer browsers option to Browserslist config. Use browserslist key in package.json or .browserslistrc file. Using browsers option can cause errors. Browserslist config can be used for Babel, Autoprefixer, postcss-normalize and other tools. If you really need to use option, rename it to overrideBrowserslist. Learn more at: https://github.com/browserslist/browserslist#readme https://twitter.com/browserslist [23:41:41] Finished 'htmlMini' after 364 ms [23:41:43] Finished 'cssMini' after 2.69 s [23:41:44] Finished 'jsMini' after 2.88 s [23:41:44] Finished 'default' after 3 s
-
8、webpack
模块打包器,核心思想是"一切皆模块"。
初学 webpack,目标是掌握 webpack 的基本使用(开发环境和生产环境),了解常用的 loader 和 plugin,能够编写 webpack 配置文件。
-
webpack安装
新创建一个目录,右键,选择在终端打开,即可在命令行工具中直接进入该目录
# npm初始化 npm init -y # 安装webpack和webpack-cli # 安装到项目下,而不是全局安装,可防止不同项目依赖不同版本的Webpack而导致冲突 npm install --save-dev webpack webpack-cli # 查看版本(新手不要怀疑,就是npx,不是npm) npx webpack --version # 这条也是查看版本 .\node_modules\.bin\webpack -v # 版本显示 webpack: 5.74.0 webpack-cli: 4.10.0 webpack-dev-server not installed
-
和 babel、gulp 一样,webpack 也有一个专门的配置文件:
webpack.config.js
,一下是一个完整的示例:"use strict"; // 引入path const path = require("path"); // 引入插件 const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry:'./src/index.js', output:'./dist/main.js', mode:'production', module:{ rules:[ { test: /\.js$/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, exclude: /node_modules/, }, ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ] }
-
简单的webpack实例
-
webpack.config.js
"use strict"; // 引入node内置路径模块path const path = require("path"); module.exports = { // 指定入口文件 entry: "./src/index.js", output: { // __dirname是当前文件的绝对路径,path.join将__dirname和'dist'组合成新的路径 // 将构建好的文件命名为'bundle.js`,输出到'./dist'目录 path: path.join(__dirname, "dist"), filename: "bundle.js", // 每次构建前清理'./dist'目录 clean: true }, mode: "production", };
-
创建一个 src 目录,创建
helloWorld.js
和index.js
两个 js 文件,代码如下:// helloWorld.js export function helloWorld() { return "Hello webpack"; }
// index.js // 引入helloWorld import { helloWorld } from "./helloWorld"; console.log(helloWorld());
-
在根目录下运行webpack构建命令
# 执行webpack构建(新手不要怀疑,就是npx,不是npm) npx webpack # 显示构建过程 asset bundle.js 55 bytes [emitted] [minimized] (name: main) orphan modules 62 bytes [orphan] 1 module ./src/index.js + 1 modules 139 bytes [built] [code generated] webpack 5.65.0 compiled successfully in 225 ms
-
另一种构建方式:
先在package.json文件里添加:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"webpack" },
再在根目录下运行构建命令:
# 执行webpack构建 npm run build
-
在dist目录下新建一个index.html文件,查验一下是否构建成功
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script src="./bundle.js"></script> </body> </html>
在浏览器中,打开
index.html
文件,查看控制台输出,看看引入的bundle.js
是否正确执行。
-
9、webpack补充
-
依赖图
构建时会顺着路径找依赖,不断加入到依赖图里,包括css样式、js代码以及图片和字体等。
-
entry
entry 指定了构建输入
上述示例是单入口写法,多入口写法有两种,一种是依次列出来,另一种是以数组的形式呈现:
"use strict"; const path = require("path"); module.exports = { //... entry:{ app:'./src/app.js', adminApp:'./src/adminApp.js', about:'./src/about.js', }, output: { path: path.join(__dirname, "dist"), // 不需要指定filename // filename: "bundle.js", clean: true, }, mode: "production", //... }
"use strict"; const path = require("path"); module.exports = { // 多入口,数组 entry: ["./src/app.js", "./src/adminApp.js", "./src/about.js"], output: { path: path.join(__dirname, "dist"), // 不需要指定filename // filename: "bundle.js", clean: true, }, mode: "production", };
与对象的区别是:
- 传入数组时,只生成一个名为
main
的 chunk; - 传入对象时,会生成多个 chunk,每个 chunk 的名称是对象对应属性的 key 名。
- 传入数组时,只生成一个名为
-
output
output 指定 webpack 如何将编译后的文件输出到磁盘;
- 单入口的情况: 最基础的,只需要指定 path 和 filename;
- 多入口的情况: 默认情况下,入口 chunk 的输出文件名是从 output.chunkFilename 中提取出来的,但我们也可以为特定的入口指定一个自定义输出文件名:
module.exports = { //... // [name]为占位符 entry: { app: './src/app.js', adminApp:'./src/adminApp.js', about: { import: './src/about.js', filename: 'cAuth/[name].js' }, }, output:{ path: path.join(__dirname, "dist") } };
运行 webpack 构建后,dist 目录下会出现
./dist/cAuth/about.js
这个输出文件;(自己尝试过之后,把 src 目录的文件恢复到helloWorld.js
和index.js
) -
loaders
webpack 不引入 loader 时,它只支持 js 和 json 文件; loader 能让 webpack 支持其他文件类型,并把它们转换成有效的模块,而且可以添加到依赖图中;
loader 可以看成一个函数,它接受源文件作为参数,返回转化后的结果;
1、babel-loader
- 先安装
babel-loader
,babel/core
和preset
:
# @babel/core 和 @babel/preset-env 应该不陌生了吧 npm install -D babel-loader @babel/core @babel/preset-env
- 在
webpack.config.js
里配置babel-loader
"use strict"; const path = require("path"); module.exports = { entry: "./src/index.js", output: { path: path.join(__dirname, "dist"), filename: "bundle.js", clean: { keep: "index.html", // 保留 index.html }, }, mode: "production", module: { rules: [ { // 对js文件使用use中的loader test: /\.js$/, use: { loader: "babel-loader", options: { // 可以直接在这里配置babel的presets,不需要编写babel.config.json了 presets: ["@babel/preset-env"], }, }, // 目录排除node_modules,提升babel转译速度 exclude: /node_modules/, }, ], }, };
- 为了直观的看到
babel-loader
转译结果,我们更改下helloWorld.js
的代码:
export function helloWorld() { const msg = 2 ** 3; return `Hello webpack for ${msg} times!`; }
- 运行
npm run build
,查看构建好的bundle.js
:
(()=>{"use strict";var o;console.log((o=Math.pow(2,3),"Hello webpack for ".concat(o," times!")))})();
可以看到,构建后的文件,已经是完成了 babel 转换; 控制台中输出的内容也变成了
Hello webpack for 8 times!
.2、sass-loader
上面我们使用了
babel-loader
,接着我们把sass
也和webpack
组合起来使用:- 安装需要的 loader:
npm install -D style-loader css-loader sass-loader sass
sass-loader
: 加载 Sass/SCSS 文件并将他们编译为 CSS
css-loader
: 加载 CSS
style-loader
: 把 CSS 代码注入到 DOM 中- 在
webpack.config.js
中,增加scss
文件的 loader 配置:
module: { rules: [ { // 对js文件使用use中的loader test: /\.js$/, use: { loader: "babel-loader", options: { // 可以直接在这里配置babel的presets,不需要编写babel.config.json了 presets: ["@babel/preset-env"], }, }, exclude: /node_modules/, }, { test: /\.scss$/, // 链式调用,链会逆序执行: scss文件,先经过sass-loader转换,再经由css-loader转换,最后交由style-loader处理 use: ["style-loader", "css-loader", "sass-loader"], exclude: /node_modules/, }, ], },
- 我们在 src 目录下,新增一个
main.scss
样式文件:
body { background-color: aquamarine; .new { width: 200px; height: 200px; background-color: red; } }
- 然后在
index.js
里引入main.scss
:
import "./main.scss";
- 更改
dist
目录下的index.html
,增加一个类名为new
的 div :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <!-- 新增一个div --> <div class="new"></div> <script src="./bundle.js"></script> </body> </html>
- 运行
npm run build
,构建bundle.js
; - 在浏览器中打开
index.html
文件,查看效果:
- 每个 loader 都有一些可配置的参数,比如我们可以在
css-loader
中,打开sourceMap
输出:
// 注意到写法的改变, css-loader 这时候得写到一个对象里; { test: /\.scss$/, use: [ "style-loader", { loader: "css-loader", options: { sourceMap: true } }, "sass-loader", ], exclude: /node_modules/, },
- webpack 的配置是比较复杂的,本文档主要也是介绍了核心的概念和基础的写法,后面项目中,编写
webpack.config.js
时,可以多去看看使用到的 loader 和 plugin 的文档,里面提供的参数可能就能解决我们的某个需求;
- 先安装