likes
comments
collection
share

构建系列之webpack窥探下

作者站长头像
站长
· 阅读数 12

  Webpack实线

安装

全局安装webpack

npm install -g webpack

进入项目目录,生成package.json文件

npm init

//对应的package.json文件
{
  "name": "test",
  "version": "1.0.0",
  "description": "package.json test",
  "main": "webpack.config.js",
  "dependencies": {
    "webpack": "^4.46.0"
  },
  "devDependencies": {},
  "scripts": {
  "build": "webpack"  //加上这一句,当我们执行npm run build时它会去我们局部的webpack中去寻找命令,如果找不到再去全局寻找
  },
  "author": "jianghuxiuxing",
  "license": "ISC"
}

安装webpack依赖

npm install webpack --save-dev

编译打包

新建index.html

// 在页面中引入test.js
<script src="test.js"></script>

新建入口文件main.js

alert('hello world')

编译main.js并打包到test.js

webpack main.js test.js

// 此时会自动生成test.js文件
// 运行index.html将弹出:hello world

新建模块module.js,并修改main.js

// module.js
module.exports = 'It is module.js!'

// main.js
alert('hello world');
alert(require('./module.js')) 

// 再次编译打包,后刷新页面
// 其它模块可同样类似引入

css文件处理

loader是webpack中一个非常核心的概念,前面提到loader是主要用来做文件转化的。虽然js代码我们可以用webpack处理并且webpack会自动处理js之间相关的依赖。但是在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。对于webpack本身的能力来说,对于这些转化是不支持的,所以就需要给webpack扩展对应的loader。

loader使用过程:

步骤一:通过npm安装需要使用的loader

步骤二:在webpack.config.js中的modules关键字下进行配置

大部分loader我们都可以在webpack的官网中找到,并且学习对应的用法。

引入css loader

npm install css-loader style-loader

去掉loader前缀

// 通过新建文件webpack.config.js
var webpack = require('webpack')
module.exports = {
  entry: './main.js',
  output: {
    path: __dir,
    filename: 'test.js'
  },
  module: {
    loaders: [
      {test: /.css$/, loader: 'style-loader!css-loader'}
    ]
  }
}

在main.js中引入style.css

require("./style.css")

引入less loader 

需要安装对应的loader。注意:我们这里还安装了less,因为webpack会使用less对less文件进行编译。其次,修改对应的配置文件,添加一个rules选项,用于处理.less文件

npm install --save-dev less-loader less
{
    test: /.css$/, 
    use: [{loader:'style-loader'},{loader:'css-loader'},
    {loader:'less-loader'}
    ]
}

ES6语法处理

在没有引入babel等能力的时候,webpack打包后的js文件的ES6语法并没有转成ES5,那么就意味着可能一些对ES6还不支持的浏览器没有办法很好的运行我们的代码。在webpack中,通过babel-loader的方式来接入babel的能力,babel配置文件与单独使用babel时相同。

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

在webpack中使用babel时建议开启babel的缓存能力,即cacheDiretory,统计显示,在大型项目中,构建速度可以提升近1倍,webpack的配置文件示例如下:

 module: {
    rules: [
      {
        test: /.[j,t]sx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader?cacheDirectory'
        }
      }
    ]
  }

监听

webpack main.js test.js --watch

webpack扩展 

webpack基于其强大的扩展能力,可以让开发者更轻松的定制化实现需求。如果你在社区找不到你的应用场景的解决方案,那就需要自己动手了写loader或者plugin了。

webpack loader,以comment-require-loader为例:

module.exports = function (content) {
    return replace(content);
};

loader的入口需要导出一个函数,这个函数要干的事情就是转换一个文件的内容。函数接收的参数content是一个文件在转换前的字符串形式内容,需要返回一个新的字符串形式内容作为转换后的结果,所有通过模块化导入的文件都会经过loader。从这里可以看出loader只能处理一个个单独的文件而不能处理代码块。

webpack plugin的两个核心概念:

  • compiler:从webpack启动到退出只存在一个Compiler,compiler存放着webpack的配置。
  • compilation:由于webpack的监听文件变化自动编译机制,compilation代表一次编译。

Compiler 和 Compilation 都会分发一系列事件。webpack生命周期里有非常多的事件,开发者可以根据对应的事件节点定制自己的功能​。

以end-webpack-plugin为例:

class EndWebpackPlugin {

    constructor(doneCallback, failCallback) {
        this.doneCallback = doneCallback;
        this.failCallback = failCallback;
    }

    apply(compiler) {
        // 监听webpack生命周期里的事件,做相应的处理
        compiler.plugin('done', (stats) => {
            this.doneCallback(stats);
        });
        compiler.plugin('failed', (err) => {
            this.failCallback(err);
        });
    }
}

module.exports = EndWebpackPlugin;

常见的loader

  • babel-loader:把es6转成es5;
  • css-loader:加载css,支持模块化,压缩,文件导入等特性;
  • style-loader:把css代码注入到js中,通过dom操作去加载css;
  • eslint-loader:通过Eslint检查js代码;
  • image-loader:加载并且压缩图片;
  • file-loader:文件输出到一个文件夹中,在代码中通过相对url去引用输出的文件;
  • url-loader:和file-loader类似,文件很小的时候可以base64方式把文件内容注入到代码中。
  • source-map-loader:加载额外的source map文件,方便调试。

常见的plugin

  • uglifyjs-webpack-plugin:通过UglifyJS去压缩js代码;
  • commons-chunk-plugin:提取公共代码;
  • define-plugin:定义环境变量。

loader和plugin的不同

作用不同:

  • loader让webpack有加载和解析非js的能力;
  • plugin可以扩展webpack功能,在webpack运行周期中会分发很多事件,plugin可以监听这些事件,并调用webpack提供的相应的api丰富现有的能力。

用法不同:

  • loader在module.rule中配置。类型为数组,每一项都是Object;
  • plugin是单独配置的,类型为数组,每一项都是plugin实例,参数通过构造函数传入。

总结 

在前端卷的无法自拔的情形下,各大脚手架或构建工具层出不穷,最近的Turbopack更是宣扬自己比webpack快700倍,虽说真实场景和数据可信度暂且不论,就形与势来说我们不能仅专注一个构建工具的使用,更不能只停留在表层不深入研究其原理。但不管是老旧项目难以更新换代脱离webpack的束缚,还是webpack本身的不断进化,我们总之是可以看到webpack的架构扩展、插件化等优秀理念的,所以我们要时刻保持着敬畏之心,毕竟技术的推陈出新也是踩在巨人的肩膀上完成的,技术没有银弹,我们需要根据自己的场景选择适用于当下及未来一段时间内的可控变化权衡后​所选用的技术。微信首发构建系列之webpack窥探下,欢迎关注微信公众号。