webpack

109 阅读6分钟

webpack里一切皆模块,一个模块对应着一个文件。

一、安装、使用webpack

  • npm init -y (生成package.json文件,-y可以省略掉不停的yes)
  • npm install -D webpack (安装webpack插件 -D是--save-dev的缩写)
  • npm install -D webpack-cli (webpack命令行)
  • 根目录添加webpack.config.js(配置文件)
  • npm script定义webpack任务("start": "webpack --config webpack.config.js")

二、webpack Loader

Loader可以看作具有文件转换功能的翻译员,告诉webpack在遇到哪些文件时用哪些Loader去加载和转换

配置loader注意事项

  • use属性的值需要是一个由Loader组成的数组,Loader的执行顺序默认是由后向前的
  • 每一个Loader可以通过UERL querystring的方式传入参数,例如css-loader?minimize中的minimize告诉css-loader要开启css压缩。

常用的loader

  • 转换样式文件:style-loader、css-loader、sass-loader、less-loader、postcss-loader
  • 加载图片、字体等文件:raw-loader、file-loader、url-loader
  • 编译转换脚本语言:babel-loader、ts-loader、coffee-loader
  • 检查测试代码:eslint-loader、tslint-loader、mocha-loader测试用例代码
1.style-loader

定义:将模块导出的内容作为样式并添加到 DOM 中。

内部使用了模块热替换功能来加载css,幕后使用了module.hot.accept。

2.css-loader

定义:加载 CSS 文件并解析 import 的 CSS 文件,最终返回 CSS 代码

webpack是用JS写的,运行在node环境,所以默认webpack打包的时候只会处理JS之间的依赖关系,不原生支持解析css文件。要支持非js类型的文件,需要使用webpack的Loader机制。 .css文件需要css-loader去处理。 css-loader会处理 import / require() @import / url 引入的内容。

注意:style-loader应该在css-loader前面(use里的loader从左到右被配置,从右到左先配置,即loader执行顺序为从右到左)。

先使用css-loader读取css文件,再使用style-loader把css内容注入到js里。
    module.exports={
        module:{
            rules:[
                {
                    test:/\.css$/i,
                    use:['style-loader','css-loader']
                }
            ]
        }
    }

三、wabpack plugin

Plugin是用来扩展webpack功能的。给webpack带来了很大的灵活性。 webpack的插件是面向配置的,而不是面向过程的。

gulp是面向过程的
gulp.src('某些源文件')
    .pipe(处理一)
    .pipe(处理二)
    .pipe(处理三)
    .dest('构建结果')

1.extract-text-webpack-plugin

作用:提取js代码里的CSS到一个单独的文件

安装依赖:npm install -D extract-text-webpack-plugin 配置webpack

    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    module.exports={
        module:{
            rules:[
                {
                    test:/\.css$/i,
                    use:ExtractTextPlugin.extract({
                        use:['css-loader']
                    })
                }
            ]
        },
        plugins:[
            new ExtractTextPlugin({
                filename:`[name]_[contenthash:8]`,
            })
        ]
    }

四、DevServer、Source Map、模块热更替(HMR)

1.DevServer(用于开发环境)

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

运行指令:npx webpack serve(运行webpack-dev-server)

  • --open(npx webpack serve --open):dev-server启动后打开浏览器
注意:
    webpack自带命令(npx webpack --watch),运行webpack并监听文件变化,
    但是不能自动刷新浏览器,也没有hot replace

无需npm run build, 文件修改后实时编译,浏览器自动刷新更新页面,编译后不输出文件,bundle保存在内存中,挂载到server上,通过webpack协议自动刷新网页做到实时预览。

// 告知 dev server,从什么位置查找文件
module.exports = {
    devServer:{
        static:'./dist',
    }
}

2.模块热替换(HMR)

在不重新加载整个网页的情况下,通过将被更新过的模块替换老的模块。程序运行过程中替换、添加或者删除模块,而无需刷新页面。 优点:

  • 实时预览反应更快,等待时间更短
  • 不刷新浏览器能保留当前网页的运行状态,例如在使用Redux来管理数据的应用中搭配模块热替换能让代码更新时Redux中的数据保持不变 总体提高了开发效率和体验,配置完生效需要添加module.hot设置。
HMR使用方式

启用:用webpack内置的HMR插件,开启模块热替换(默认是关闭的),只需在启动DevServer时带上 --hot参数(或者用HotModuleReplacementPlugin插件来实现)。

开启模块热替换后,会有一个注入到全局的全局变量module.hot,用于控制模块热替换的逻辑.

(1)开启命令:npx webpack serve --hot。

(2)配置:

    module.exports = {
        devServer:{
            hot:true
        }
    }
react 里有react-hot-loader插件(基于 webpack-dev-server,所以还得安装 webpack-dev-server)

// module.hot配置
// 只有当开启了模块热替换时 module.hot 才存在
if (module.hot) {
  // accept 函数的第一个参数指出当前文件接受哪些子模块的替换,这里表示只接受 ./AppComponent 这个子模块
  // 第2个参数用于在新的子模块加载完毕后需要执行的逻辑
  module.hot.accept(['./AppComponent'], () => {
    // 新的 AppComponent 加载成功后重新执行下组建渲染逻辑
    render(<AppComponent/>, window.document.getElementById('app'));
  });
}

3.Source Map

背景:在浏览器运行的js都是编译后的代码,可读性差,不方便调试。source map可以映射原代码,可以在原代码上调试。开启后,打开浏览器开发者工具,source栏中就能看到源代码了。出现错误时,能定位错误,并知道错误来自于哪个源文件。

启动:

  • 命令: npx webpack serve --devtool source-map
  • 配置: module.exports = { devtool:'source-map'}
module.exports = {
  devtool:'inline-source-map'
}

五、配置

核心配置

  • entry:入口,webpack执行构建的第一步将从entry开始
  • output:输出结果,在webpack经过一系列处理并得出最终想要的代码后输出结果
  • module:模块,在webapck里一切皆模块,一个模块对应着一个文件。webpack会从配置的entry开始找出所有依赖的模块。
  • chunk:代码块,一个chunk由多个模块组合而成,用于代码合并和分割
  • loader:模块转换器,用于把模块原内容按照需求转换成webpack接受的新内容。
  • plugin:扩展插件,在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。

配置webpack的方式有两种:

  • 在js文件里配置,如webpack.config.js文件里配置
  • 执行webpack可执行文件时通过命令行参数传入,如:webpack --devtool source-map 这两种方式可互相搭配,如:通过命令 webpack --config webpack-dev.config.js指定配置文件,然后在webpack-dev.config.js文件里添加配置。

1.module

module配置如果处理模块 module.rules配置模块的读取和解析规则,通常用来配置loader。类型是array。

配置一项rules:

  • 条件匹配:通过test、include、exclude配置来命中loader要应用规则的文件
  • 应用规则:对选中后的文件通过use配置项来应用loader,可以用一个或者按照从后往前的顺序应用一组loader,还可以给loader传入参数
  • 重置顺序:一组loader的执行顺序默认是从右到左执行,可通过enforce改变顺序
// 例子
module.exports = {
    rules:[
        {  
            test:/\.js$/,  // 命中js文件
            // 用 babel-loader 转换 JavaScript 文件
            // ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存babel 编译结果加快重新编译速度
            use: ['babel-loader?cacheDirectory'],
            // 只命中src目录里的js文件,加快 Webpack 搜索速度
            include: path.resolve(__dirname, 'src')
        },
        {
          // 命中 SCSS 文件
          test: /.scss$/,
          // 使用一组 Loader 去处理 SCSS 文件。
          // 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。
          use: ['style-loader', 'css-loader', 'sass-loader'],
          // 排除 node_modules 目录下的文件
          exclude: path.resolve(__dirname, 'node_modules'),
        },
        {
          // 对非文本文件采用 file-loader 加载
          test: /.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
          use: ['file-loader'],
        },
    ]
}

在loader需要传入很多参数时 ,可以通过一个object来描述

use: [
  {
    loader:'babel-loader',
    options:{
      cacheDirectory:true,
    },
    // enforce:'post' 的含义是把该 Loader 的执行顺序放到最后
    // enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面
    enforce:'post'
  },
  // 省略其它 Loader
]

另外,test、include、enclude这三个命中文件的配置项还可以支持数据类型。 数组中的每一项都是或的关系,即文件路径符合数组中的任何一个条件就会命中。

2.resolve

其他

深入浅出wepack:webpack.wuhaolin.cn/

玩转 Webpack:极客时间视频time.geekbang.org/course/deta…

webpack实战书

2.资源管理 type:asset/resource

{
    test:/.(png|svg|jpg|jpeg|gif)$/i,
    type:'asset/resource'
}

3.plugin: htmlwebpackplugin 创建一个html,并将所有的 bundle 会自动添加到 html 中

4.clean 清理 /dist 文件夹

output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   }

6.开发环境:webpack-dev-server

7.代码分离:webpack最引人注目的特性之一

8.缓存:输出文件名用hash

moudle.exports = {
    output:{
        filename:'[name].[contenthash].bundle.js'
    }
}

10.webpack可以打包js library

library依赖的第三方库(比如lodash),将控制权给library的consumer(使用者)

module.exports = {
    output:{
        library:{
            name:'webpackNumbers',
            type:'umd',  // 使库可以与 CommonJS、AMD 以及 script 标签使用
        }
    },
    externals:{
        lodash:{
            commonjs:'lodash',
            commonjs2:'lodash',
            amd:'lodash',
            root:'_'
        }
    }
}

11.环境变量 --env

npx webpack --env goal=local --env production --progress

--env production 默认表示将 env.production 设置为 true

module.exports 转换成一个函数,能获取到env

const path = require('path');

module.exports = (env) => {
  // Use env.<YOUR VARIABLE> here:
  console.log('Goal: ', env.goal); // 'local'
  console.log('Production: ', env.production); // true

  return {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist'),
    },
  };
};