webpack

webpack中,有一些地方要用绝对路径的:地址

一.认识webpack工具

事实上随着前端的快速发展,目前前端的开发已经变的越来越复杂了:

  比如开发过程中我们需要通过模块化的方式来开发;

  比如也会使用一些高级的特性来加快我们的开发效率或者安全性,比如通过ES6+、TypeScript开发脚本逻辑,通过sass、less等方式来编写css样式代码;

  比如开发过程中,我们还希望实时的监听文件的变化来并且反映到浏览器上,提高开发的效率;

  比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化

  等等….

但是对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中根本就没有面临这些问题:

  这是因为目前前端开发我们通常都会直接使用三大框架来开发:Vue、React、Angular

  但是事实上,这三大框架的创建过程我们都是借助于脚手架(CLI)的

  事实上Vue-CLI、create-react-app、Angular-CLI都是基于webpack来帮助我们支持模块化、less、TypeScript、打包优化等的;

 

二.webpack是什么?

webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序;

  打包bundler:webpack可以将帮助我们进行打包,所以它是一个打包工具

  静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);

  模块化modulewebpack默认支持各种模块化开发,ES Module、CommonJS、AMD等;

  现代的modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展;

vue项目加载的文件有哪些呢?

  JavaScript的打包:

    将ES6转换成ES5的语法;

    TypeScript的处理,将其转换成JavaScript;

  Css的处理:

    CSS文件模块的加载、提取;

    Less、Sass等预处理器的处理;

  资源文件img、font:

    图片img文件的加载;

    字体font文件的加载;

  HTML资源的处理:

    打包HTML资源文件;

  处理vue项目的SFC文件.vue文件;

三.webpack基本打包

前面我们直接执行webpack命令使用的是全局的webpack,如果希望使用局部的可以按照下面的步骤来操作。

  第一步:创建package.json文件,用于管理项目的信息、库依赖等.   :  npm init

  第二步:安装局部的webpack. :   npm install webpack webpack-cli -D

  第三步:使用局部的webpack. :   npx webpack

  第四步:在package.json中创建scripts脚本,执行脚本打包即可  [npm run build]   

{

  "script":{

    "build" : " webpack --config wk.config.js"

  }

}

    

四.webpack配置文件

 我们可以在根目录下创建一个webpack.config.js文件,来作为webpack的配置文件:

 

但是如果我们的配置文件并不是webpack.config.js的名字,而是其他的名字呢?

  这个时候我们可以通过 --config 来指定对应的配置文件 : webpack --config wk.config.js

但是每次这样执行命令来对源码进行编译,会非常繁琐,所以我们可以在package.json中增加一个新的脚本: [npm run build]

{

  "script":{

    "build" : " webpack --config wk.config.js"

  }

}

五.编写和打包css文件

什么是loader ?

  loader 可以用于对模块的源代码进行转换;

  我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;

  在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能;

配置loader?

const path = require("path")

module.exports = {
  // 入口
  entry: "./src/main.js",
  // 出口
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build")
  },
  // 配置loader
  module: {
    rules: [
      {
        test: /\.css$/,  // text : 告诉webpack匹配什么文件
        use: [ // use中多个loader的使用顺序是从后往前
          { loader: "style-loader" },
          { loader: "css-loader" }
        ],
      },

      // 简写一: 如果loader只有一个
      {
        test: /\.css$/,
        loader: "css-loader"
      },
      
      // 简写二: 多个loader不需要其他属性时, 可以直接写loader字符串形式
      {
        test: /\.css$/, 
        use: [
          "style-loader",
          "css-loader", 
          "postcss-loader"
        ],
      },
    ]
  }
}

 

读取css文件常用的loader : css-loader  

  安装 :  npm install css-loader -D

将css插入到页面用的loader  : style-loader   [css是通过页内样式的方式添加进来的]

  安装 : npm install style-loader -D

 

less 文件 常用的loader :  npm install less-loader -D

先用  less-loader , 再用 css-loader , 最后用  style-loader

 

 postcss

  是一个通过JavaScript来转换样式的工具 , 可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置;

  但是实现这些功能,我们需要借助于PostCSS对应的插件;

如何使用PostCSS呢?

  1:查找PostCSS在构建工具中的扩展,比如webpack中的postcss-loader; 

      安装 : npm install postcss-loader -D

  2:选择可以添加你需要的PostCSS相关的插件;

      安装 :  npm install postcss-preset-env -D      

        它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill;

        也包括会自动添加浏览器前缀

const path = require("path")

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build")
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 
          { loader: "style-loader" },,
          { loader: "css-loader" }, 
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  "postcss-preset-env"
                ]
              }
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: [ "style-loader", "css-loader", "less-loader", "postcss-loader" ]
      }
    ]
  }
}

 

也可以将这些配置信息放到一个单独的文件中进行管理 : 在根目录下创建postcss.config.js

module.exports = {
  plugins: [
    require("postcss-preset-env")
  ]
}

 

六.打包图片

const path = require("path")

module.exports = {
  // 入口
  entry: "./src/main.js",
  // 出口
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
  },
  // 配置loader
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        // 1.打包两张图片, 并且这两张图片有自己的地址, 将地址设置到img/bgi中
        // 缺点: 多图片加载的两次网络请求
        // type: "asset/resource",

        // 2.将图片进行base64的编码, 并且直接编码后的源码放到打包的js文件中
        // 缺点: 造成js文件非常大, 下载js文件本身消耗时间非常长, 造成js代码的下载和解析/执行时间过长
        // type: "asset/inline"

        // 3.合理的规范: [最好的]
        // 3.1.对于小一点的图片, 可以进行base64编码
        // 3.2.对于大一点的图片, 单独的图片打包, 形成url地址, 单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 60 * 1024
          }
        },
        // 定义文件名
        generator: {
          // 占位符 name: 指向原来的图片名称
          // ext: 扩展名
          // hash: webpack生成的hash
          filename: "img/[name]_[hash:8][ext]"
        }
      },
    ]
  },
}

 

七.打包JS代码

 

八.babel和babel-loader

babel : 可以将es6转换为es5 ; 可以转换TypeScript

  安装 :  npm install @babel/cli @babel/core -D

  安装 :  npm install babel-loader -D

如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset

webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel

  安装 : npm install @babel/preset-env

 

const path = require("path")

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    // assetModuleFilename: "abc.png"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          { 
            loader: "babel-loader", 
            options: {
              presets: [
                "@babel/preset-env"
              ]
            } 
          }
        ]
      },
    ]
  },
}

 

九.认识插件Plugin

Plugin : 可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等
 
1.HtmlWebpackPlugin
我们的HTML文件是编写在根目录下的,而最终打包的dist文件夹中是没有index.html文件的。在进行项目部署的时,必然也是需要有对应的入口文件index.html;
所以我们也需要对index.html进行打包处理;
  使用插件 :  npm install html-webpack-plugin -D
 
2.DefinePlugin
DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装)
例子 : <link rel="icon" href="<%= BASE_URL %>favicon.ico">
BASE_URL : 就是通过DefinePlugin 配置的
 
3..mode模式配置
Mode配置选项,可以告知webpack使用相应模式的内置优化:
 默认值是 production(什么都不设置的情况下);
 可选值有:'none' | 'development' | 'production';
const path = require("path")

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require("webpack")

module.exports = {
  mode: "production",
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    clean: true //不用再手动删除dist文件夹
  },
  plugins: [
    new HtmlWebpackPlugin({
      // 标题 : 在index 通过 <%= htmlWebpackPlugin.options.title %> 读
      title: "电商项目",
      // 自己定义的模板
      template: "./index.html"
    }),
    
    // 全局可用的 : 
    new DefinePlugin({
      BASE_URL: "'./'",
      coderwhy: "'why'",
      counter: "123"
    })
  ]
}

 

十.开启本地服务器

  安装webpack-dev-server  : npm install webpack-dev-server -D

  修改配置文件package.json 的  "serve": "webpack serve --config wk.config.js"

  1.HMR热模块替换

    devServer: {
      hot: true, // 开启热更新
    }
  2.devServer配置
const path = require("path")

module.exports = {
  mode: "development",
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./build"),
    clean: true
  },
  devServer: {
    hot: true,  // 开启热更新
    host: "0.0.0.0", //主机地址 : 希望其他地方也可以访问,可以设置为 0.0.0.0
    port: 8888, //设置监听的端口,默认情况下是8080
    open: true, //open是否打开浏览器:
    compress: true //是否为静态文件开启gzip compression
  }
}
 
localhost 和 0.0.0.0 的区别:
  localhost:本质上是一个域名,通常情况下会被解析成127.0.0.1;
  127.0.0.1:回环地址(Loop Back Address),表达的意思其实是我们主机自己发出去的包,直接被自己接收;
    正常的数据库包经常 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层 ;
    而回环地址,是在网络层直接就被获取到了,是不会经常数据链路层和物理层的;
    比如我们监听 127.0.0.1时,在同一个网段下的主机中,通过ip地址是不能访问的;
  0.0.0.0:监听IPV4上所有的地址,再根据端口找到不同的应用程序;
    比如我们监听 0.0.0.0时,在同一个网段下的主机中,通过ip地址是可以访问的;

 

十一.Proxy(Vue项目学习)

proxy是我们开发中非常常用的一个配置选项,它的目的设置代理来解决跨域访问的问题:
  比如我们的一个api请求是 http://localhost:8888,但是本地启动服务器的域名是 http://localhost:8000,这个时候发送网络请求就会出现跨域的问题;
  那么我们可以将请求先发送到一个代理服务器,代理服务器和API服务器没有跨域的问题,就可以解决我们的跨域问题了;
我们可以进行如下的设置:
  target:表示的是代理到的目标地址,比如 /api-hy/moment会被代理到 http://localhost:8888/api-hy/moment;
  pathRewrite:默认情况下,我们的 /api-hy 也会被写入到URL中,如果希望删除,可以使用pathRewrite;
  secure:默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false;
  changeOrigin:它表示是否更新代理后请求的headers中host地址;

 

十二.changeOrigin的解析(Vue项目学习)

这个 changeOrigin官方说的非常模糊,通过查看源码我发现其实是要修改代理请求中的headers中的host属性:
  因为我们真实的请求,其实是需要通过 http://localhost:8888来请求的;
  但是因为使用了代码,默认情况下它的值时 http://localhost:8000;
  如果我们需要修改,那么可以将changeOrigin设置为true即可;

 

十三.historyApiFallback (Vue项目学习)

  historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在路由跳转之后,进行页面刷新时,返回404的错误。
  boolean值:默认是false
    如果设置为true,那么在刷新时,返回404错误时,会自动返回 index.html 的内容;
  object类型的值,可以配置rewrites属性:
    可以配置from来匹配路径,决定要跳转到哪一个页面;
  事实上devServer中实现historyApiFallback功能是通过connect-history-api-fallback库的:
 

十四.如何区分开发环境

目前我们所有的webpack配置信息都是放到一个配置文件中的:webpack.config.js
  当配置越来越多时,这个文件会变得越来越不容易维护;
  并且某些配置是在开发环境需要使用的,某些配置是在生成环境需要使用的,当然某些配置是在开发和生成环境都会使用的;
  所以,我们最好对配置进行划分,方便我们维护和管理;
那么,在启动时如何可以区分不同的配置呢?
  方案一:编写两个不同的配置文件,开发和生成时,分别加载不同的配置文件即可;
  方式二:使用相同的一个入口配置文件,通过设置参数来区分它们;

 

入口文件的解析

我们之前编写入口文件的规则是这样的:./src/index.js,但是如果我们的配置文件所在的位置变成了 config 目录,我们是否应该变成 ../src/index.js呢?
  如果我们这样编写,会发现是报错的,依然要写成 ./src/index.js;
  这是因为入口文件其实是和另一个属性时有关的 context;
context的作用是用于解析入口(entry point)和加载器(loader):
  官方说法:默认是当前路径(但是经过我测试,默认应该是webpack的启动目录)
  另外推荐在配置中传入一个值; 

 

区分开发和生成环境配置 , 这里我们创建三个文件:
  webpack.comm.conf.js
  webpack.dev.conf.js
  webpack.prod.conf.js 

 

posted @ 2022-08-09 12:04  杨建鑫  阅读(28)  评论(0编辑  收藏  举报