webpack

266 阅读10分钟

实验代码请看我的github项目webpack-demo-1

webpack是使用框架前必会的工具

webpack的作用

  1. 转译代码(ES6转为ES5, SCSS转为CSS)
  • 把我们写的高级的最新版的浏览器还不懂的js代码,转译成浏览器可以读懂的js代码
  1. 构建build
  2. 代码压缩
  3. 代码分析

安装webpack

  1. 在命令行局部安装:npm i -g webpack@4 webpack-cli@3

  2. 注意要在后面加上版本号

  3. 可以用npm info webpack

  • 查看一个包的所有信息
  • bin:webpack 可执行文件叫webpack
  • dist-tags :版本号

在一个文件夹里引入webpack

去官网,点击DOCUMENTATION → GUIDES → Getting Started

  1. 新建webpack-demo-1
  2. 给该文件夹里引入webpack

在命令行

npm init -y  //创了一个package.json
yarn add webpack webpack-cli --dev  //多了一个node_modules目录

如何运行使用打包webpack

我们不是全局安装webpack,所以在命令行

  • 方法一:./node_modules/.bin/webpack 我们把webpack引入在webpack-demo-1文件夹,所以写全路径
  • 方法二:npx webpack npx会帮你在本地找到,但是不太稳定,如果不能用就用方法一
  1. 运行webpage后会默认创建dist目录

如何用webpack转义js

设置webpage.config.js

  • 新建webpage.config.js
  • 写内容
var path = require("path");

module.exports = {
  mode: "development", //转译后的低级文件的样子。development给开发者看,有注释;production给用户用,没任何注释,体积很小。
  entry: "./src/index.js", //入口:你想要转译哪个高级js文件,不写就会默认./src/index.js
  output: {
    //出口:
    path: path.resolve(__dirname, "dist"), //转译后的低级js文件放在新建的dist目录,不写默认都是这样的
    filename: "[name].[contenthash].js" //转译后的低级js文件的名字,只要高级文件更新了,重新打包后就会再新建一个低级文件,文件名也是新的。(所以要把之前的旧的低级文件删掉)
  }
};

作用

把高级js文件,自动生成dist文件夹,里面有转译好的低级js文件

例子

  • 新建src/index.js,这就是我们即将要转义的高级js文件
  • 运行webpacknpx webpack
  • 出现了dist目录,里面有个main.xxxxx.js,这就是转译后的低级js文件

http缓存

我们请求baidu.com,百度服务器响应我们index.html,浏览器读到index.html里面又会向百度服务器请求1.css、2.css、1.js、2.js,也就是把他们下载下来。如果把1.css、2.css、1.js、2.js下载后保存到浏览器的内存(memory cache或者disk cache)里,那下次在请求baidu.com,响应index.html,就不用再又去百度服务器请求这些css和js了,直接从内存里拿出来用

  • 问题一:浏览器如何把这个css和js保存在自己的内存中?

百度服务器在这些请求的响应头里写cache-Control:public max-age:3153600。表示我百度服务器,同意公开我的这个css和js响应体,你们浏览器可以在第一次请求后直接把他保存在你们浏览器的内存里。浏览器可以保存一年。

浏览器知道响应头里这样写之后,就会自动保存到自己内存了。

  • 问题二:要是服务器里面更新了这个css和js文件,浏览器之前保存的该咋办?

在webpack的config里面写

var path = require("path");

module.exports = {
  mode: "development", 
  entry: "./src/index.js", 
  output: {
    path: path.resolve(__dirname, "dist"), 
    filename: "[name].[contenthash].js" //转译后的低级js文件的名字,是个哈希表
  }
};

只要高级js文件被更新,当我们重新打包时,就重新转译,在dist里面就会有一个新的文件名不一样的低级js文件。(所以我们要提前把之前的dist文件和里面的旧的低级js文件删掉)

这样当浏览器读到index.html里面引用的js文件(名)跟以前不一样了,自动舍弃以前的,把新的下载后保存到内存里

  • 为啥index.html不会被浏览器保存?

要是把index.html保存下来,里面引用的js、css文件名也一年不变了,那你咋知道css和js更新了,有了新的文件名了??

memory cache 不请求网络资源,资源在内存当中,一般脚本、字体、图片会存在内存当中

disk cache 不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css等

被我禁用从缓存里读文件后,就必须从服务器下载,整个响应时间都长了

重新设置打包webpack:每次打包时,自动把旧的dist和里面的低级文件删掉

  1. 普通方法:先rm -rf dist在打包npx webpack
  2. 高级方法:一键搞定上面两步
  • 首先,在package.json里
"scripts": {
    "build": "rm -rf dist && webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  • 之后,每次只需yarn bulid就相当于删除了dist同时又运行使用打包webpack了

HTML(搜webpack create html page)

设置webpack.config.js

  1. 在命令行,安装插件html-webpack-plugin yarn add html-webpack-plugin --dev
  2. 设置webpack.config.js
var HtmlWebpackPlugin = require("html-webpack-plugin"); 
//②在dist目录里新建一个html文件,这个html文件会自动引入也在dist目录里的低级js文件
  plugins: [
    new HtmlWebpackPlugin({
      title: "My App", //修改html文件的title
      template: "src/assets/admin.html" //html文件的模板是我们写的src/ assets / admin.html。所以我们可以把html模板写好:都改成中文zh,用淘宝的view point!
      //如果想让我们的模板里还用我们这里设置的title,就在模板里的title写<%= htmlWebpackPlugin.options.title %>插件里的options里的title
    })
  ]

作用

在dist里生成一个html文件,这个html文件里自动引入了dist文件里的低级js文件

CSS

(一)使用js生成style标签(搜webpack css loader)(在开发时使用)

做法

  1. 在命令行,安装包 yarn add css-loader --dev yarn add style-loader --dev

  2. 设置webpack.config.js

module: {
    rules: [
      {
        test: /\.css$/i, //发现了任何以.css结尾的文件
        use: ["style-loader", "css-loader"] //css-loader会把这个css文件的内容读到高级js文件里,style-loader会把css内容放入script标签,再放入
      }
    ]
  }
  1. 这样就可以在高级js文件里引入css文件(import './x.css'),就不会报错了

作用

在高级js文件里引入css文件(import './x.css')

在dist目录的html文件的head里用script引入css内容

(二)把CSS抽成文件(搜 webpack extract plugin)(在上线build后使用)

做法

  1. 安装插件yarn add mini-css-extract-plugin --dev
  2. 在webpack.config.js里
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//③②
 plugins: [
    //③②找到我们自己的css文件变成dist目录里新建的一个css文件(也可缓存,像js一样),而且dist里的html也会自动引用这个css文件
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css",
      ignoreOrder: false
    })
  ],
  //③
  module: {
    rules: [
      {
        test: /\.css$/i, //发现了任何以.css结尾的文件
        //③①用js的话:css-loader会把这个css文件的内容读到高级js文件里,style-loader会把css内容放入script标签,再放入dist里的html文件的head里
        //use: ["style-loader", "css-loader"]
        //③②用插件抽成文件的话
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../",
              hmr: process.env.NODE_ENV === "development"
            }
          },
          "css-loader"
        ]
      }
    ]
  }

作用

首先在高级js文件里引入css文件(import './x.css')

变成dist目录里新建的一个css文件(也可缓存,像js一样),而且dist里的html也会自动引用这个css文件

预览(搜webpack dev server)

  1. 低级写法:在dist目录里http-server . -c-1,记得如果要重新打包必须返回根目录
  2. 使用webpack dev server,以后yarn start(npm start)就可以预览,而且自动刷新。而且不用yarn build打包了。他会默默给你打包好然后预览,所以开发时候用yarn start预览(+打包),需要上线就yarn build
  • 在webpack.config.js
mode:"development",
devtool: 'inline-source-map'
  • 在命令行安装yarn add webpack-dev-server --dev

  • 在webpack.config.js

devServer: {
    contentBase: "./dist"
  },
  • 在package.json
"start": "webpack-dev-server --open",

两个模式,两个config,一个公共config

原来的在一起的config

//①代表js
//②代表html
//③代表css--①代表用js ②代表用插件

var path = require("path"); //①
var HtmlWebpackPlugin = require("html-webpack-plugin"); //②
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //③②

module.exports = {
  //①新建dist目录,里面是转译后的低级js文件
  mode: "development", //development给开发者看,有注释;production给用户用,没任何注释,体积很小。
  entry: "./src/index.js", //入口:你想要转译哪个高级js文件,不写就会默认./src/index.js
  output: {
    //出口:
    path: path.resolve(__dirname, "dist"), //转译后的低级js文件放在新建的dist目录,不写默认都是这样的
    filename: "[name].[contenthash].js" //转译后的低级js文件的名字
  },

  //关于webpack server dev
  devtool: "inline-source-map",
  devServer: {
    contentBase: "./dist"
  },

  plugins: [
    //②在dist目录里新建一个html文件,这个html文件会自动引入也在dist目录里的低级js文件
    new HtmlWebpackPlugin({
      title: "My App", //修改html文件的title
      template: "src/assets/admin.html" //html文件的模板是我们写的src/ assets / admin.html。所以我们可以把html模板写好:都改成中文zh,用淘宝的view point!
      //如果想让我们的模板里还用我们这里设置的title,就在模板里的title写<%= htmlWebpackPlugin.options.title %>插件里的options里的title
    }),
    //③②找到我们自己的css文件变成dist目录里新建的一个css文件(也可缓存,像js一样),而且dist里的html也会自动引用这个css文件
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash].css",
      chunkFilename: "[id].css",
      ignoreOrder: false
    })
  ],
  //③
  module: {
    rules: [
      {
        test: /\.css$/i, //发现了任何以.css结尾的文件
        //③①用js的话:css-loader会把这个css文件的内容读到高级js文件里,style-loader会把css内容放入script标签,再放入dist里的html文件的head里
        //use: ["style-loader", "css-loader"]
        //③②用插件抽成文件的话
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../",
              hmr: process.env.NODE_ENV === "development"
            }
          },
          "css-loader"
        ]
      }
    ]
  }
};

公共config

//开发和上线的config的共有属性都在这里

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.[contenthash].js"
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "哈哈哈",
      template: "src/assets/index.html"
    })
  ],
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ["file-loader"]
      },
      {
        test: /\.styl$/,
        loader: ["style-loader", "css-loader", "stylus-loader"]
      },
      {
        test: /\.less$/,
        loader: ["style-loader", "css-loader", "less-loader"]
      },
      {
        test: /\.scss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("dart-sass")
            }
          }
        ]
      }
    ]
  }
};

开发模式的config

  1. 用本来的webpack.config.js当开发时的config
  2. yarn start预览(偷偷打包)
  3. 开发时我们需要
  • mode:development
  • 用js变成script标签里的css(快啊,不用打包)
//开发时要用的
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
const base = require("./webpack.config.base.js"); //引入共有的

module.exports = {
  ...base, //先把所有base抄过来
  mode: "development", //增加mode
  devtool: "inline-source-map", //关于webpage server dev
  devServer: {
    contentBase: "./dist"
  },
  module: {
    rules: [
      ...base.module.rules, ////我的module的rules内容是和base一样,并且增加我的css use
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"]
      }
    ]
  }
};

上线模式的config

  1. 新建webpack.config.prod.js当上线时的config
  2. yarn build打包就是上线了,需要在他的设置里加上他的config是webpack.config.prod.js,不然默认的都是webpack.config.js "build": "rm -rf dist && webpack --config webpack.config.prod.js",
  3. 上线时我们需要
  • mode:production
  • 打包的css文件,因为需要缓存,每次更新需要改文件名啊
//上线时用的
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const base = require("./webpack.config.base.js"); //继承base

module.exports = {
  ...base, //先把所有base抄过来
  mode: "production", //增加mode
  plugins: [
    ...base.plugins, //我的插件内容是先抄base的插件内容,在增加我的插件
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash].css",
      chunkFilename: "[id].[contenthash].css",
      ignoreOrder: false
    })
  ],
  module: {
    rules: [
      ...base.module.rules, //我的module的rules内容是和base一样,并且增加我的css use
      {
        test: /\.css$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../"
            }
          },
          "css-loader"
        ]
      }
    ]
  }
};

小结

思路图

webpack的loader和plugin的区别

  1. loader是加载器,用来加载某些资源文件。内置的babel-loader是用来把js加载成低版本浏览器支持的js;css-loader和style-loader是用来加载css,把它变成页面中的style标签。图片用来加载图片,把他做些优化
  2. plugin是插件,用来加强webpack的功能。比如HTML-webpack-pligin用来生成HTML文件,mini-css-extract-plugin用来把多个css文件生成一个css文件。

SCSS(搜webpack sass loader)

(scss就是包含兼容css,所以把css的后缀改成less就行)

做法

  1. 安装loader:sass-loaderdart-sass

yarn add sass-loader dart-sass --dve

注:不要用node-sass,已经过时,用dart-sass 2. 在webpack.config.base.js

  module: {
    rules: [
      {
        test: /\.scss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("dart-sass")
            }//把sass代码转化成css代码,之后再把css转化经过两步转化成style标签
          }
        ]
      }
    ]
  1. 这样就可以在高级js文件里引入scss文件了(import 'x.scss'

LESS

(LESS就是包含兼容css,所以把css的后缀改成less就行)

做法

  1. 安装loader:less-loaderless

yarn add less-loader --dve yarn add less --dev

  1. 在webpack.config.base.js
  module: {
    rules: [
      {
        test: /\.less$/,
        loader: ["style-loader", "css-loader", "less-loader"] //把less代码转化成css代码,之后再把css转化经过两步转化成style标签
      },
    ]
  1. 这样就可以在高级js文件里引入less文件了(import 'x.less'

stylus

(stylus就是包含兼容css,所以把css的后缀改成less就行)

做法

  1. 安装loader:stylus-loaderstylus-loader: yarn add stylus-loader stylus --dev
  2. 在webpack.config.base.js
  module: {
    rules: [
      {
        test: /\.styl$/,
        loader: ["style-loader", "css-loader", "styl-loader"] //把styl代码转化成css代码,之后再把css转化经过两步转化成style标签
      },
    ]
  1. 这样就可以在高级js文件里引入styl文件了(import 'x.styl'

图片

做法

  1. 安装loader:file-loader

yarn add file-loader --dve

  1. 在webpack.config.base.js
  module: {
    rules: [
   {
        test: /\.(png|svg|jpg|gif)$/,
        use: ["file-loader"] //把文件变成文件路径
      },
    ]
  1. 这样就可以在高级js文件里引入图片文件了
import png from "./assets/1.png"; //png就是这个图片的路径(这是file-loader做的)

const div = document.getElementById("app");

div.innerHTML = `<img src="${png}">`;

懒加载

不得不加载的时候才去加载 不想一开始就加载某个模块。因为体积太大。 如何实现懒加载:用import(js路径)去加载模块,会得到一个promise(异步),promise.then前面写成功干什么,后面写失败干什么。

部署到github

先yarn build 先切换到dist目录,用http server . -c-1本地预览成功 就可以上传到github

方法一:用master

把dist目录一起上传,用github pages预览

方法二:用分支

  1. 从方法一过来,就在.gitignore里加入dist,删掉dist目录。记得上传
  2. 重新yarn build。记得上传
  3. 新建分支git branch gh-pages,专门用来预览
  4. 切入该分支git checkout gh-pages,除了dist和node_modules和.gitignore都删掉。再把dist里所有文件弄出来到当前目录(gh-pages分支)mv dist/* ./,再删掉dist目录,提交
  5. 在Github Pages 里选gh-pages分支预览预览即可
  6. 在master分支写一个部署脚本文件deploy.sh(记得上传),这样就可以一键部署:先提交(好习惯),在sh deploy.sh
yarn build &&  //得到最新的dist
git checkout gh-pages &&
rm -rf *.htm *.js *.css *.png &&   //这不是第一次进入该分支,所以第一次进入时已经把除了dist gitignore node_modules 之外的都删了(存疑),下次进入该分支只需要把上次的从dist目录弄出来的html js css png删掉就行
mv dist/* ./ && 
rm -rf dist  ;
git add . &&
git commit -m "update" &&
git push &&
git checkout -  //回到上一个分支