C4云原生——【一】前端工程化基础学习笔记

前端云原生学习笔记

一、前端工程化基础

1、node与npm

  1. node版本建议10以上,用node -v查看版本,npm -v查看npm的版本,现在的node安装的时候会自动装npm

  2. 装好之后默认的获取地址是淘宝,需要修改

    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转译

  1. 选择路径,新建项目文件夹,并进入该文件夹

    cd 路径
    
    mkdir filename
    
    cd filename
    
  2. 初始化项目

    npm init
    

    然后一路回车,descriptionauthor想写就写一点,结束之后会生成一个package.json文件

  3. 编写配置文件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"
      ]
    }
    

    知道插件地址就行,不过有一点点麻烦

  4. 在终端命令行执行,创建src.js文件,并在vsCode中打开编辑:

    code src.js
    

    src.js中写入所需ES6代码

  5. 打开package.json文件,添加实时监控

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "babel-watch": "babel src.js --watch --out-file dist.js"
      },
    
  6. 保存babel/core,否则后面run会报错"找不到babel/core"

    npm install --save-dev @babel/core
    
  7. 在终端执行,监控src.js代码变化,并实时转译

    npm run babel-watch
    
    # ctrl+c 可以退出watch监控
    终止批处理操作吗(Y/N)? y
    

至此,即达到实时编写转译。

4、Sass——CSS预处理器

  1. 安装Sass

    # npm全局安装sass, 这样在其他项目里,也能直接调用,不需要重新安装
    npm install -g sass
    
    # 查看版本,确定安装成功
    sass --version
    > 1.44.0 compiled with dart2js 2.14.4
    
  2. 初始化样式

    # 安装reset-css
    npm install --save reset-css
    

    然后在src/main.scss引入reset css,进行样式的初始化,同时设置box-sizingborder-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.cssmain.css.map两个文件,main.css大家很熟悉,main.css.map是 SourceMap 文件。

    • 我们查看下main.css,可以发现 reset 样式已经写入其中;
    • 在浏览器中打开index.html文件,可以看到reset-css已经生效。
  3. 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、编写样式

  1. 嵌套

    可以让样式的书写能直接对应上html元素的层级,编写和维护都更加清晰。

  2. 变量

    将主题颜色拎出来赋值给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;
          }
        }
      }
    }
    
  3. 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;
    }
    
  4. 继承

    注意:不可以跳父级继承,只能继承同一个爸爸的样式属性!

    继承了之后,补上不同的地方要写的代码即可。

    .order {
      /* 属性继承 */
      @extend .tutor;
      background-color: #e8e8e8;
      color: #111111;
      float: right;
    }
    
  5. 模块

    在使用原生 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 文件,比如分成基础全局样式、特定布局样式、全局变量值等,更便于开发和维护。

  6. 注释

    scss 文件中的注释有如下两种:

    • 标准的 CSS 注释 /* comment */ ,会保留到编译后的文件
    • 单行注释 // comment,只保留在 scss 文件中,编译到 css 文件后,会被省略
    • 重要注释:在/*后面加一个感叹号,表示这是"重要注释"。即使是压缩模式编译,也会保留这行注释
    /*!
        这是重要注释!
      */
    
  7. 计算

    在 scss 样式文件里,我们可以直接进行某些样式值的计算:

    @use "sass:math"; // 引入sass内置的math模块
    
    width: math.div(600, 960) * 100%;
    

    还原设计稿的时候,有些计算起来比较麻烦的值,就不用自己先计算出来了。

  8. 其他 Sass 特性

    Sass 还有很多其他的功能,包括丰富的内置函数(颜色函数等)、允许用户自定义函数等,感兴趣的自己拓展.

    Sass 中文网

6、Babel 与 Sass 组合使用

  1. 增加 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;
        }
      }
    }
    
  2. 构建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 来读取和操作数据。

  1. 安装 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
    
  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 配置文件。

  1. 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
    
  2. 和 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'
        })
      ]
    }
    
  3. 简单的webpack实例

    1. 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",
      };
      
    2. 创建一个 src 目录,创建helloWorld.jsindex.js两个 js 文件,代码如下:

      // helloWorld.js
      export function helloWorld() {
        return "Hello webpack";
      }
      
      // index.js
      // 引入helloWorld
      import { helloWorld } from "./helloWorld";
      
      console.log(helloWorld());
      
    3. 在根目录下运行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
      
    4. 另一种构建方式:

      先在package.json文件里添加:

      "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "build":"webpack"
        },
      

      再在根目录下运行构建命令:

      # 执行webpack构建
      npm run build
      
    5. 在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补充

  1. 依赖图

    构建时会顺着路径找依赖,不断加入到依赖图里,包括css样式、js代码以及图片和字体等。

  2. 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 名。

    webpack Entry 文档

  3. 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.jsindex.js)

    webpack output 文档

  4. loaders

    webpack 不引入 loader 时,它只支持 js 和 json 文件; loader 能让 webpack 支持其他文件类型,并把它们转换成有效的模块,而且可以添加到依赖图中;

    loader 可以看成一个函数,它接受源文件作为参数,返回转化后的结果;

    1、babel-loader

    • 先安装babel-loader,babel/corepreset:
    # @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文件,查看效果:

    20220301151249

    • 每个 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 的文档,里面提供的参数可能就能解决我们的某个需求;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

键盘里的咬肌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值