浅谈webpack

155 阅读7分钟

使用CRM方法搞webpack,C(copy)、R(run)与M(modify);

目标一:实现转译Js

  • 1.打开官网:webpack.js.org/guides/gett… 看启动步骤
  • 2.npm install webpack webpack-cli --save-dev安装webpck 与 webpack-cli,上个命令时本地安装webpack与webpack-cli,安装后如果要查看版本号不能直接使用webpack --version命令,需要找到其在本项目的安装目录再使用命令./node_modules/.bin/webpack --version;这样需要打很多字,可以使用npx webpack --version代替;
  • npx 想要解决的主要问题,就是调用项目内部安装的模块。npx 的原理很简单,就是运行的时候,会到node_modules/.bin路径和环境变量path里面,检查命令是否存在。由于 npx 会检查环境变量path,所以系统命令也可以调用。
  • 运行webpaccknpx webpack,以下就是目录结构

在dist文件夹下面多了个main.js;

打开main.js我们发现,除了我们写的console.log('webpack run')以外,还有很多其他的代码,这是因为 webpack会分析代码,会把代码编译成IE或者低版本的浏览器可以用的版本,都是写兼容代码,来保证我们使用的es6语法可以在浏览器正常运行;

  • 控制台出现了警告
  • 为了解决这个警告,我们打开官网,新建一个js文件webpack.config.js,

  • 这是mode为'development'模式,编译打包后的main.js代码是如下样子

  • 如果mode为''production'模式,main.js代码是下面样子

这是因为development模式是开发模式,用于开发者开发;production模式是生产模式,用于线上运行;

目标二:理解文件中hash的用途

  • 1.按照官方文档设置入口文件与出口文件,运行后报如下错误

当我们不设置能正常运行,设置后报入口找不到,首先因为我们没有foo.js,第二说明入口默认设置的地址就是src/index.js

修改后正常运行,而且我们发现dist目录下面有个新的js,名字是foo.bundle.js,这是由于我们设置的出口的文件名字是foo.bundle.js;

  • 我们把出口的js文件名字改为main.js,并且把原来的dist目录删掉,因为怕生成的新的与旧的分不清楚;

再次运行

我们进一步修改,如果入口文件是index.js,你想变成出口的也是index.js,那么可以设置出口名字为index.js,由于路径是默认的放到dist下面,我们也可以删除此时设置的path

再次运行后

  • 一般为了防止浏览器缓存,我们会在文件后面加hash值,那webpack是如何加的呢,请看下面的配置

  • 下面我们讲解下http缓存的问题 定义:当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。
    HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。
    1. 没有缓存:Cache-Control: no-store
    2.缓存但重新验证 Cache-Control: no-cache每次有请求发出时,缓存会将此请求发到服务器(译者注:该请求应该会带有与本地缓存相关的验证字段),服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。
  1. 过期:过期机制中,最重要的指令是 "max-age=",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改;Cache-Control: max-age=31536000
  • 那怎么更新已经缓存的文件内容呢,由于http是根据文件名称来缓存的,因此我们可以只改变文件名称就可以了,也就是我们上次的增加Hash值;
  • 请注意:首页是一定不能缓存的

当我们修改文件内容,每次打包都会生成一个新的带有hash的文件,这会出现很多老的文件,那我们应该怎么办呢?

  • 我们可以在package.json里面的scripts增加一个命令:"build": "rm -rf dist; webpack"
  • 在控制台输入npm run build

目标三:在webpack自动生成html

  • 在官网搜索关键字“create html”,进入此网站https://webpack.js.org/plugins/html-webpack-plugin/#root
  • npm install --save-dev html-webpack-plugin 安装html-webpack插件 运行后,dist文件夹多了个html文件,里面自动连接了打包后的js

  • 但是现在的html对我们来说没有用处,因为我们想定制自己的html,可用下面的配置

目标四:引入css

  • 新增一个css文件,并在js中引入css

运行的时候报错,提示要安装cssloader ,ok,去官网找资料吧

  • npm install --save-dev css-loader 安装 css-loader 与style-loader

css-loader 的作用是把css代码引入到js中,style-loader的作用是自动生成style标签并把css内容放到标签里面;

使用webpack-dev-server

  • webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)

  • 运行npm install --save-dev webpack-dev-server
  • 其他配置https://www.webpackjs.com/guides/development/ 看这个网址的配置
  • 需要注意的是:这个工具的用途是当你改代码不需要重新build,也不需要删除之前的代码,并不是帮我们生成dist目录,而是在内存搞定,读取我们的src/index.js,转换成可以运行的代码,然后放入内存中,而不是硬盘,因为硬盘太慢了,这样开发速度就加快了。

目标五:webpack引入css,并抽成文件

  • 搜索‘webpack css extract plugin’
  • 运行sudo npm install mini-css-extract-plugin -D

挑战五:不同的环境访问不同的webpack-config文件

  • 配置package.json

  • 新建生成所用的配置文件
  • 配置webpack,开发所用的配置文件,开发的时候,css是直接写入header里面
  • 配置生成webpack,css以链接的方式

  • 但是上面代码会遇到一个问题,两个配置文件有很多重复一样的代码,我可以使用继承的思想,提取公共的代码;新建一个名字为webpack.config.base.js的文件
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'index.[contenthash].js'
  },
  plugins: [new HtmlWebpackPlugin({
    template:'./src/index.html'
  })],
  module: {
    rules: [
    ],
  }
}


webpack.config.js 的代码如下

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let base = require("./webpack.config.base");
module.exports = {
  ...base,
  mode:'development',
  devtool: 'inline-source-map',
  devServer: {
       contentBase: './dist'
 },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  }
}

webpack.config.prod.js 的代码如下

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
let base = require("./webpack.config.base");
module.exports = {
  ...base,
  mode:'production',
  plugins: [
    ...base.plugins,
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
    }),],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  }
}

运行正常

webpack loader 与webpack plugin的区别是什么?

  • 翻译:loader是加载器,plugin是插件
  • 解释加例子:加载器就是加载文件,比如babel-loader是用来加载js,style-loader是用来加载css;插件是用来扩展webpack功能的,比如htmlwebpackPlugin用来生成html文件;

目标六:引入scss

  • npm install sass-loader dart-sass webpack --save-dev主要不要安装node-sass,而是sass-loader webpack.config.base.js新增如下配置
module: {
    rules: [{
      test: /\.scss$/,
      use: [{
        loader: "style-loader" // 将 JS 字符串生成为 style 节点
      }, {
        loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
      }, {
        loader: "sass-loader", // 将 Sass 编译成 CSS
        options: {implementation:require('dart-sass')}
      }]
    }]
  }

webpack.config.js 的代码如下

module: {
    rules: [
      ...base.module.rules,
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  }

webpack.config.prod.js 的代码如下

module: {
    rules: [
      ...base.module.rules,
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  }

新增一个scss文件,并在index.js中引入

目标七:引入less与stylus

  • npm install --save-dev less-loader less stylus-loader stylus
  • base配置文件内容
 module: {
    rules: [{
      test: /\.scss$/,
      use: [{
        loader: "style-loader" // 将 JS 字符串生成为 style 节点
      }, {
        loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
      }, {
        loader: "sass-loader", // 将 Sass 编译成 CSS
        options: {implementation:require('dart-sass')}
      }]
    },
      {
        test: /\.styl$/,
        use: ['style-loader','css-loader','stylus-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader','css-loader','less-loader']
      }
    ]
  }

目标八:引入图片

  • 使用file-loader,可把文件变为文件路径

目标九:实现懒加载 import()函数

  • import()方法使用了promise式的回调,获取加载的包,这个功能可以实现按需加载我们的代码