Webpack入门(3) - 核心内容

webpack入门(2)-安装,配置,环境,上节传送门。

Entry(入口)

简单提一下,Entry是webpack的入口文件,一开始运行webpack它会找到webpack.config.js里的Entry。它会从这开始着手,构建内部依赖图。入口点可以有一个或多个。

entry的类型

  • string类型
    一个入口
    entry:'./src/main.js'
  • array类型
    配置了多个入口
    entry: ['./src/main1.js', './src/main2.js']
  • object类型
    对象类型
    entry: {
      a: './src/main.js',
      b: ['./src/main1.js', './src/main2.js']
    }
  • 多个入口时,每个入口生成都会生成Chuck。
  • 如果是array类型,则搭配output.library配置项使用时,只有数组里的最后一个入口文件会被导出。

配置动态Entry

假如项目里有多个页面需要为每个页面的入口配置一个entry,但这些页面数量可能会不断增长,这时entry的配置会受到其他因素的影响导致不能写成静态的值。解决办法就是把entry设置成一个函数去动态返回上面所说的配置:

//同步函数
entry: () => {
    return {
        a: './pages/a',
        b: './pages/b'
    }
}

//异步函数
entry: () => {
    return new Promise((resolve) => {
        resolve({
            a: './pages/a',
            b: './pages/b'
        })
    })
}

output

Output属性告诉webpack在哪里输出它所创建的bundles,也可指定bundles的名称,默认位置为./dist。整个应用结构都会被编译到指定的输出文件夹中去,你可以通过在配置中指定一个 output 字段,来配置这些处理过程。最基本的属性包括filename(文件名)和path(输出路径)。

Chuck的名称

向上面的main.js中,main就是Chuck名称。Chunk的名称和Entry的配置有关。

  • 如果entry是string类型或者是array类型,只会生成一个Chuck。
  • 如果entry是一个object,就可能出现多个chunk,这时候的chunk值是object名称。比如上面的a.js,b.js。Chuck名称在output可以配置。

    多个入口时怎么配置filename

    当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle的时候,可以有以下几种赋bundle名称的方式。
  • 使用入口名称赋值,[name]为entry的key值,比如a.bundle.js,b.bundle.js
    filename: "[name].bundle.js"
  • 使用内部 chunk id,从0开始
    filename: "[id].bundle.js"
  • 使用每次构建过程中,都会生成一段Hash值
    filename: "[name].[hash].bundle.js"
  • 使用基于每个 chunk 内容的 hash值,可以理解为版本号(Git里面的)或者md5值。文件内容发生改变,chunkhash就会改变。在这里可以用到:项目上线,只上线那些被改过的文件
    filename: "[chunkhash].bundle.js"
    取5位Hash值,默认为20位。
    filename: "[chunkhash:5].bundle.js"

    path

    output.path 配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。通常通过 Node.js 的 path 模块去获取绝对路径:
    path: path.resolve(__dirname, 'dist_[hash]')
    __dirname就是当前文件所在的文件夹的名字。

    publicPath

    对构建出的资源进行异步加载(图片,文件)。加载这些异步资源需要对应的 URL 地址。默认值是空字符串“ ”。简单说,就是静态文件托管在cdn上。
    如果你这么配置:
    output:{
      filename:'[name]_[chunkhash:8].js',
      publicPath:'https://www.qdtalk.com/assets/'
    }
    打包编译之后,HTML页面就变成了这个:
    <script src="https://www.qdtalk.com/assets/a_12345678.js"></script>
    上面只是举了output的几个常用参数。

Loader

Loader在webpack中承担翻译的工作。
因为webpack自身只支持加载jsjson文件,把源文件转化翻译后输出新结果,且一个文件还可以链式的经过多个翻译员翻译

以处理SCSS文件为例:

  • SCSS 源代码会先交给 sass-loaderSCSS 转换成 CSS
  • sass-loader 输出的 CSS 交给 css-loader 处理,找出 CSS 中依赖的资源、压缩 CSS 等;
  • css-loader 输出的 CSS 交给 style-loader 处理,转换成通过脚本加载的 JavaScript 代码。

    常用的Loader

  • 样式:style-loader、css-loader、less-loader、sass-loader等。
  • 文件:raw-loader、file-loader 、url-loader
  • 编译:babel-loader、coffee-loader 、ts-loader
  • 校验测试:mocha-loader、jshint-loader 、eslint-loader
  • vue-loader、coffee-loader、babel-loader等可以将特定文件格式转成js模块、将其他语言转化为js语言和编译下一代js语言
  • file-loader、url-loader等可以处理资源,file-loader可以复制和放置资源位置,并可以指定文件名模板,用hash命名更好利用缓存。
  • url-loader可以将小于配置limit大小的文件转换成内敛Data Url的方式,减少请求。
  • raw-loader可以将文件已字符串的形式返回
  • imports-loader、exports-loader等可以向模块注入变量或者提供导出模块功能
  • expose-loader:暴露对象为全局变量

    安装Loader

    以安装css-loader和style.loader为例,直接在终端:
    npm install css-loader style-loader --save-dev

    配置单个Loader

    webpack.config.js
    module.exports = {
      module: {
          rules: [
              {
                  test: /\.css$/,
                  use: 'css-loader'
              }
          ]
      }
    }
  • test:后面接一个正则表达式,表示有那些后缀文件被处理。
  • use:表示应该用什么loader。

配置多个loader

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

其他配置方法

  • 直接在命令行
    webpack --module-bind 'txt=raw-loader'
  • 内联
    import txt from 'raw-loader!./file.txt'
    但这两种方法都不推荐。还是在webpack.config.js配参数更好。

几个重要的loader

Babel

Babel 可以让你使用ES2015/16/17 写代码而不用顾忌浏览器的问题,Babel 可以帮你转换代码。

  • 安装几个必要的Babel库,
    npm i --save-dev babel-loader babel-core babel-preset-env
    babel-loader让webpack去处理一些使用了es6的js文件。
    babel-core 提供一系列API,其实是让babel-loader去调用babel-core的API。
    babel-preset-env 这个库可以根据环境的不同转换代码
  • 配置babel规则。在package.json里面增加一个babel属性。作用是设置项目中的babel转码规则和使用到的babel插件,格式如下:
    "babel":{
    "presets": ["evn"],//设定转码规则
    "plugins": []//要用到的插件
    }
    表示告诉npm,在本项目中将使用babel,并且使用babel-preset-env规则进行转码。
  • 除了上一种写法外,还有另外一种方法(推荐写法)。在根目录下面新建.babelrc文件,然后做一下配置:
    {
    "presets": ["babel-preset-env"]
    }
    
- 上面已经配置好`babel`的规则,但是`webpack`依然不知道何时使用该规则。我们还要再接着在配置里写入

use: ‘babel-loader’

**但要注意的是**,只有`js`文件才可以使用`babel`。

### 处理图片
- `npm i --save-dev url-loader file-loader`
- 在`webpack.config.js`里面修改配置:

test: /.(png|jpe?g|gif|svg)(?.*)?$/,
use : [
{
loader: ‘url-loader’,
options: {
// 限制 图片大小 10000B,小于限制会将图片转换为 base64格式
limit: 10000,
// 超出限制,创建的文件格式
// build/images/[图片名].[hash].[图片格式]
name: ‘images/[name].[hash].[ext]’
}
}
]


# Plugins(插件)
插件用来拓展webpack功能,可以用于执行范围更广的任务,包括**打包、优化、压缩、搭建服务器**等等,功能十分强大。**要是用一个插件,一般是先使用npm包管理器进行安装,然后在配置文件webpack.config.js中require引入,最后在这个文件下使用new来创建一个实例。**   Loader一次只能处理单个相同类型的文件,但是plugins可以对整个过程起作用。
## 常用的plugin插件
- webpack内置`UglifyJsPlugin`插件,压缩和混淆代码。
- webpack内置`CommonsChunkPlugin`,提高打包效率,将第三方库和业务代码分开打包
- `ProvidePlugin`:自动加载模块,代替`require`和`import`
- `html-webpack-plugin`可以根据模板自动生成html代码,并自动引用css和js文件
- `extract-text-webpack-plugin` 将js文件中引用的样式单独抽离成css文件
- `DefinePlugin` 编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用。
- `HotModuleReplacementPlugin `热更新
- `optimize-css-assets-webpack-plugin` 不同组件中重复的css可以快速去重
- `webpack-bundle-analyzer` 一个webpack的bundle文件分析工具,将bundle文件以可交互缩放的treemap的形式展示
- `compression-webpack-plugin` 生产环境可采用gzip压缩JS和CSS
- `happypack`:通过多进程模型,来加速代码构建
## 一个简单的插件使用
- `npm install --save-dev html-webpack-plugin`安装一个插件。有的插件webpack自带,如果没有,则需用npm安装。
- `const HtmlWebpackPlugin = require('html-webpack-plugin');`在webpack.config.js中引入。
- new一个实例

plugins: [

new HtmlWebpackPlugin({
template: ‘./src/index.html’, //以src目录下的index.html文件为模板生成html5新文件
filename: ‘index.html’,//指定生成的HTML文件叫啥名
inject: ‘head’,//指定把脚本script标签放在那里,这里放在标签里。还可以放
})
]

## 利用html-webpack-plugin插件自动生成html文件
### 为什么要自动生成HTML
每次执行webpack打包生成js文件后,都必须在index.html中手动插入打包好的文件的路径。**但在真实生产环境中,一次运行webpack后,完整的index.html应该是被自动生成的。** 例如静态资源、js 脚本都被自动插入了。
### 根目录下的index.html文件
根目录下的index.html会被html-webpack-plugin作为最终生成的 html 文件的模板。打包后,相关引用关系和文件路径都会按照正确的配置被添加进去。
### 配置

const HtmlWebpackPlugin = require(“html-webpack-plugin”);

module.exports = {
entry: {
app: “./src/app.js”
},
output: {
publicPath: dirname + “/dist/“,
path: path.resolve(
dirname, “dist”),
},
plugins: [
new HtmlWebpackPlugin({
filename: “index.html”,
template: “./index.html”,
chunks: [“app”], // entry中的app入口才会被打包
minify: {
// 压缩选项
collapseWhitespace: true
}
})
]
}

最后执行打包命令,然后在dist目录下就给你自动生成了index.html文件。dist目录下的index.html文件是以根目录下的inde.html文件为模板的。

# 其他几个核心概念
## Module(模块)
对于webpack,模块不仅仅是javascript模块,它包括了任何类型的源文件,不管是图片、字体、json文件都是一个个模块。**Webpack支持以下的方式引用模块:**
- ES2015 import 方法
- CommonJs require() 方法
- AMD define 和 require 语法
- css/sass/less文件中的 @import 语法
- url(...)和 <img src="">的图片路径
## Dependency Graph(依赖关系图)
所谓的依赖关系图是webpack根据每个模块之间的依赖关系递归生成的一张内部逻辑图,有了这张依赖关系图,webpack就能按图索骥把所有需要模块打包成一个bundle文件了。
## Mode(模式)
分为开发模式`development`和生产模式`production` 。两种模式的区别在于一个是为生产环境编译打包,一个是为了开发环境编译打包。生产环境模式下,webpack会自动对代码进行压缩等优化,省去了配置的麻烦。

## 结语
webpack断断续续终于算是入门了。与其他技能点相比,webpack算是比较酸涩难懂。但是学无止境,我学webpack的还有很长的路要走。

  目录