webpack概述

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler )

webpack中文网

webpack官网

webpack做了什么

  • 语法转换
    • less/sass转换成css
    • ES6转换成ES5
    • typescript转换成js
  • html/css/js代码的压缩与合并(打包)
  • webpack可以在开发期间提供一个开发环境
    • 自动开启浏览器
    • 自动监视文件变化
    • 自动刷新浏览器
  • 项目一般都需要经过webpack打包之后才上线。

webpack模块说明

webpack会把所有的资源都当成模块

  • css
  • js
  • 图片
  • 字体图标

webpack给前端开发提供了模块化的开发环境

1、node中的模块化语法,(commonjs规范)

require(...) module.exports=....

2、浏览器中模块化语法

seajs 国内,淘宝出的,(CMD规范)

requirejs 国外的(AMD规格)

...慢慢被淘汰了

3、es6中的模块化语法(模块化语法规范)

import export

目前,浏览器还是node,都不支持es6的语法,利用webpack可以转换为node语法

  • 对于js文件,webpack中支持AMD、CMD、commonJS、ES6模块化等语法
  • 有了webpack,我们可以在前端代码中使用任意的模块化语法
  • 可以在浏览器中使用nodejs的模块化语法const $ = require('jquery')

webpack使用步骤

  • 建目录
./dist 打包后的文件目录
./src 自己的项目源码
  • 项目初始化
yarn init -y
  • 安装依赖

    --save 早起npm安装包时 如果不加--save,不会记录到package.json中,从npm5版本开始已经默认自动记录可以省略

    --save-dev 会将包名记录到 devDependencies 中

    dependencies :项目依赖,代码中依赖的包,实际上线需要使用

    devDependencies:开发依赖,只在开发阶段需要使用的包,项目上线不需要使用

yarn add webpack webpack-cli -D  
  • 配置package.json中的 scripts脚本

    在package.json中可以配置 scripts脚本,配置命令如下,使用命令运行比如:npm run xxx

    特殊命令:start stop 可以省略 run

    npm run start => npm start

    npm run stop =>npm stop

    yarn中所有命令都可以省略 run

  "scripts": {
     //命令名称 	 //需要打包的文件路径    //打包后的文件路径   //压缩模式
    "build": "webpack ./src/index.js  -o ./dist/bundle.js  --mode=production"
  },

使用配置文件的情况下

"scripts": {
     //命令名称
    "build": "webpack"
  },
  • 使用命令
yarn build  # 就可以使用webpack进行打包了

配置文件-webpack.config.js

如果所有的参数都拼接到webpack-dev-server的后面,非常的麻烦,因此可以提供webpack.config.js来进行配置

  • 在项目的根目录下面新建webpack.config.js文件
const path = require('path')
// 这是一个nodejs文件
module.exports = {
  // 设置入口文件,从哪个文件开始打包
  entry: path.join(__dirname, 'src/index.js'),
  // 设置出口,配置打包到哪里去
  output: {
    // 设置打包输出目录
    path: path.join(__dirname, 'dist'),
    // 输出文件的文件名
    filename: 'bundle.js'
  },
    //配置模式,建议先配置为不压缩
    mode: 'development'
}
  • 执行命令
webpack  // webpack会自动读取当前目录下的配置文件
  • 模式的配置
// 设置打包的模式
//'production' 压缩版本
//'development'  开发版本
mode: 'production'

压缩多个文件内容

在入口文件中添加需要压缩的文件,require(路径....)

压缩会把添加的文件一并压缩

webpack-插件

webpack 有着丰富的插件接口(rich plugin interface)。webpack 自身的多数功能都使用这个插件接口。这个插件接口使 webpack 变得极其灵活

html-webpack-plugin插件

我们需要将index.html模板文件打包到dist文件夹中,使用插件html-webpack-plugin完成

  • 安装
npm install html-webpack-plugin --save-dev
yarn add  html-webpack-plugin -D
  • webpack.config.js导入
var HtmlWebpackPlugin = require('html-webpack-plugin');
  • 使用
module.exports = {
    //配置插件
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'src', 'index.html')
        })
    ],
}

webpack-loaders

webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js 来很简单地编写自己的 loader。

css-loader处理css文件

  • 安装
//npm安装方式
npm install --save-dev style-loader css-loader
//yarn安装方式
yarn add style-loader css-loader -D 
  • 配置
//在webpack.config.js下面添加  
module: {
    // loader的规则
    rules: [
      {
        // 正则表达式,用于匹配所有的css文件
        test: /\.css$/,
        // 使用什么样的loader进行解析
          //css-loader可以让webpack可以解析css文件
          //style-loader 可以让css,以动态形式显示在页面
        use: [ "style-loader", "css-loader"]
      }
    ]
  },

less-loader处理less文件

  • 安装
npm install --save-dev less-loader less

yarn add less-loader less -D
  • 配置
{
    // 匹配所有的less文件
    test: /\.less$/,
        use: [ "style-loader", "css-loader", "less-loader"]
}

file-loader处理图片文件

file-loader会以单独文件的形式打包到dist目录中

  • 安装
npm install --save-dev file-loader
  • 配置
{
    // 配置图片加载
    test: /\.(png|jpg|gif|jpeg)$/,
    use: "file-loader"
}

url-loader处理图片文件

url-loader与file-loader一样,也可以处理图片,但是url-loader可以以base64编码的方式处理图片

实际,将图片转换成base64,需要成本,会让文件增大30%大小的体积,开发过程中,只会将小图片转换成base64,大图片依旧是单独的文件

  • 安装
npm install --save-dev url-loader
yarn add -D url-loader
  • 配置
{
    // 配置图片加载
    test: /\.(png|jpg|gif)$/,
        use: [
            {
                loader: 'url-loader',
                options:{
                    //限制大小 8k=8*1024 超过8k使用file-loader处理
                    limit:8*1024
                }
            }
        ]
}
  • base64的优点
1. 精灵图的作用:减小网络请求
2. base64:减少网络请求  通过京东查看base64编码的图片
  • 设置limit参数
{
    // 配置图片加载
    test: /\.(png|jpg|gif)$/,
        use: [
            {
                loader: 'url-loader',
                options: {
                    // 限定文件大小,注意:如果文件超出了大小,会自动调用file-loader,所以安装url-loader通过都要安装file-loader
                    limit: 8192
                }
            }
        ]
}

url-loader处理字体图标文件

处理字体图标文件与处理图标一模一样

  • 配置
{
    // 配置字体图标加载
    test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
        use: [
            {
                loader: 'url-loader',
                options: {
                    // 限定文件大小
                    limit: 819200
                }
            }
        ]
}
           

babel处理高版本的ES语法

介绍

Babel 是一个 JavaScript 编译器。

今天就开始使用下一代 JavaScript 语法吧!

官网

中文网

babel可以把最新版本的语法编译成浏览器能够兼容的代码(ES5)

使用

  • 安装
npm install -D babel-loader @babel/core @babel/preset-env
yarn add -D babel-loader @babel/core @babel/preset-env
  • 配置
{
    test: /\.js$/,
    //配置排除项
    exclude: /(node_modules)/,
    use: {
        loader: 'babel-loader'
    }
}

webpack-dev-server的使用

在开发期间,会用到webpack的一个辅助包:webpack-dev-server,(自动刷新,打包)

webpack-dev-server的作用

  • 自动开启http服务

  • 自动打开浏览器

  • 自动监视文件的变化

  • 引入,每次修改代码,都需要重新打包

基本使用

  • 安装
npm install --save-dev webpack-dev-server
yarn add -D webpack-dev-server
  • webpack.config.js中的scripts命令设置

  • 配置
  // webpack-dev-server提供了一个简单的服务器,并且能够实时重新加载
//在webpack.config.js中与plugins并列设置
  devServer: {
    //端口号
     port: 9999,
     //自动打开浏览器
     open: true,
     //热更新,差异化更新,更新效率高
     hot: true
  }

热更新的说明

  • 开启
hot: true
  • 配置
var webpack = require("webpack");

plugins: [
    new HtmlWebpackPlugin({
        template: path.join(__dirname,"src", 'index.html')
    }),
    new webpack.HotModuleReplacementPlugin()
],
  • 热更新与dev-server模式不会在生产环境下用,生产环境还是需要npm run build

ES6模块化

在之前的 javascript 中一直是没有模块系统的,前辈们为了解决这些问题,提出了各种规范, 最主要的有CommonJS和AMD两种。前者用于服务器,后者用于浏览器。而 ES6 中提供了简单的模块系统,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

基本使用

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个 变量,就必须使用export关键字输出该变量。下面是一个JS文件,里面使用export命令输出变量。

es6 中新增了两个命令 export 和 import , export 命令用于规定模块的对外接口(导出),import 命令用于输入其他模块提供的功能(导入)

精确导出导入

//精确导出
// a.js
export const name = 'hucc'
export const age = 18
export const desc = '很帅'

使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)

//精确导入
//main.js
import {name, age, desc} from './a.js'
console.log('从模块内部导出的内容:', name, age, desc)

export(导出)详解

上面介绍了模块化最基础的用法,export 不止可以导出函数,还可以导出对象,数组,字符串等等

//a.js
export const name = 'hucc'
export const arr = [1, 2, 3]
export const obj = {
  name: 'zs',
  age: 18
}

export的写法,除了像上面这样,还有另外一种。

//a.js
const name = 'hucc'
const arr = [1, 2, 3]
const obj = {
  name: 'zs',
  age: 18
}

//	优点:上面代码在export命令后面,使用大括号指定所要输出的一组变量。它与前一种写法是等价的,但是应该优先考虑使用这种写法。因为这样就可以在脚本尾部,一眼看清楚输出了哪些变量。
//原样
export {
    name:name,
    arr:arr,
    obj:obj
}
//简写
export {name, arr, obj}

export default 指定默认输出, import 无需知道变量名就可以直接使用

//a.js
export default function fn () {
  console.log('哈哈')
}

//main.js
//在导入时,可以随意的使用变量名来接收
import a from './a'
a()
//export default 导出一个对象
export default {aa, bb}
//在导入时,可以随意的使用变量名来接收
import a from './a'
//注意此时的变量a
a={
   aa,
   bb 
}

注意:export default是非常用的语法,用的很多, 以一些常用的模块为例

import $ from 'jQuery'   // 加载jQuery 库
import _ from 'lodash'   // 加载 lodash
import moment from 'moment' // 加载 moment

import(导入) 详解

import 为加载模块的命令,基础使用方式和之前一样

//main.js
import {name, arr, user} from './a'

//如果是export default导出的内容
import a from './a'

兼容性说明

上面介绍了,es6 中模块的使用方式,但是现在es6的模块化,无论在浏览器端还是 node.js 上都没有得到很好的支持,所以需要,一些转码的工具(babel)。使我们可以用es6的方式来编码,最后输出es5的代码。

开发项目常用配置

devServer.open(热启动)

open启用时,开发服务器将打开浏览器。

open: true

通过CLI使用

webpack-dev-server --open

如果未提供浏览器(如上所示),则将使用默认浏览器。要指定其他浏览器,只需传递其名称:

webpack-dev-server --open 'Google Chrome'

devServer.port(端口号)

指定要监听请求的端口号:

port: 8080

通过CLI使用 :

webpack-dev-server --port 8080

devServer.proxy(反向代理)

如果你有单独的后端开发服务器 API,并且希望在同域名下发送 API 请求 ,那么代理某些 URL 会很有用。

dev-server 使用了非常强大的 http-proxy-middleware 包。更多高级用法,请查阅其文档

localhost:3000 上有后端服务的话,你可以这样启用代理:

proxy: {
  "/api": "http://localhost:3000"
}

请求到 /api/users 现在会被代理到请求 http://localhost:3000/api/users

如果你不想始终传递 /api ,则需要重写路径:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    pathRewrite: {"^/api" : ""}
  }
}

默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。如果你想要接受,修改配置如下:

proxy: {
  "/api": {
    target: "https://other-server.example.com",
    secure: false
  }
}

有时你不想代理所有的请求。可以基于一个函数的返回值绕过代理。

在函数中你可以访问请求体、响应体和代理选项。必须返回 false 或路径,来跳过代理请求。

例如:对于浏览器请求,你想要提供一个 HTML 页面,但是对于 API 请求则保持代理。你可以这样做:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf("html") !== -1) {
        console.log("Skipping proxy for browser request.");
        return "/index.html";
      }
    }
  }
}

如果要代理到同一目标的多个特定路径,则可以使用一个或多个具有context属性的对象的数组:

proxy: [{
  context: ["/auth", "/api"],
  target: "http://localhost:3000",
}]