webpack实战-04-05-结合其他工具搭配使用,各取所长

143 阅读7分钟

搭配Npm Script

认识Npm Script

是一个任务执行者,Npm是安装node时候附带的包管理器,Npm Script是Npm的内置功能,允许再package.json中使用scripts字段定义任务

{
    "scripts": {
        "dev": "node dev.js",
        "build": "node build.js"
    }
}

执行npm run dev相当于执行node dev.js命令

它还可以运行安装到node_modules里的可执行模块,如有模块npm i -D webpack,我们可以:

{
    "scripts": {
        "dev": "webpack"
    }
}

为啥webpack需要Npm Script

webpack只是一个模块化打包工具,没有提供任何管理功能 举个栗子: 要求:

  • 开发阶段,需要DevServer,并且需要输出Source Map方便调试
  • 减少发布到线上的代码尺寸,构建时压缩输出的代码
  • 在构建完发布到线上的代码后,需要将构建的代码提交给发布系统

1,2冲突,3依赖2,所以可以定义三个不同的任务

{
    "scripts": {
        "dev": "webpack-dev-server --open",
        "dist": "NODE_ENV=production webpack --config webpack_dist.config.js",
        "pub": "npm run dist && rsync dist"
    }
}
  • dev:开发时执行的任务,通过DevServer启动构建
  • dist:构建出发布到线上的代码
  • pub:先构建出发布到线上的代码,再同步dist目录中的文件到发布系统

检查代码

主要检查什么

  • 代码风格
  • 潜在问题

怎么检查

检查js

最常见的工具ESlint,npm i -g eslint安装到全局后,执行eslint init来新建一个ESlint配置文件.eslintrc,文件格式为JSON,如果想覆盖默认检查规则,或者想加入新的检查规则,则需要修改该文件,例如

{
    // 从eslint:recommended中继承所有检查规则
    "extends": "eslint:recommended",
    // 再自定义一些规则
    "rules": {
        // 需要在每行结尾加
        "semi": ["error", "always"],
        // 需要使用“”包裹字符串
        "quotes": ["error", "double"]
    }
}

写好配置文件后再执行eslint 文件名.js检查这个文件

检查ts

TSlint,和ESlint相似,但是TSlint只检查ts代码

npm i -g tslint
tslint --init
tslint 文件名.js

检查CSS

stylelint,给予postcss,能检查任何postcss能解析的代码,scss,less 1、npm i -g stylelint 2、项目根目录新建.stylelintrc配置文件,JSON格式,和eslint配置相似,如

{
    // 继承stylelint-config-standard中所有的检查规则
    "extends": "stylelint-config-standard",
    // 自定义检查
    "rules": {
        "at-rule-empty-line-before": null
    }
}

3、执行stylelint "文件名.css"

结合Webpack检查代码

结合ESlint

eslint-loader:

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'eslint-loader',
                // 将eslint-loader执行顺序放到最前面,防止其他Loader将处理后的代码交给eslint-loader去检查
                enforce: 'pre'
            }
        ]
    }
}

结合TSlint

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'tslint-loader',
                // tslint-loader执行顺序放到最前面,防止其他Loader将处理后的代码交给tslint-loader去检查
                enforce: 'pre'
            }
        ]
    }
}

结合stylelint

StyleLintPlugin

const StyleLintPlugin = require('stylelint-webpack-plugin');
module.exports = {
    // ...
    plugins: [
        new StyleLintPlugin(),
    ]
}

将代码检查功能加到webpack中会导致以下问题 1、执行检查的计算量大,所以构建速度变慢 2、输出的错误信息通过行号定位,没有编辑器集成显示错误直观 解决方案: 1、使用继承了代码检查的编辑器,可以实时直观的显示错误 2、将代码检查步骤放到代码提交时,只有检查通过时才提交代码

husky可以方便快速为项目接入Git Hook,执行npm i -D husky会通过Npm Script Hook自动配置好Git Hook,我们需要做的是在package.json中定义几个脚本

{
    "scripts": {
        // 在执行git commot前会执行的脚本
        "precommit": "npm run lint",
        // 在执行git push时会执行的脚本
        "prepush": 'lint,
        // 调用eslint,stylelint等工具检查代码
        "lint": "eslint && stylelint"
    }
}

通过Node.js API启动Webpack

Webpack除了提供了可执行的命令行工具,还提供了可在Node.js环境中调用的库,通过Webpack暴露出的API,可直接再Node.js程序中调用Webpack执行构建 通过API去调用并执行Webpack,比直接通过可执行文件启动灵活

安装和使用Webpack模块

1、调用Webpack API前,需要先安装它,npm i -D webpack 2、导入Webpack模块

const webpack = require('webpack');
// es6语法
import webpack from "webpack";
// 导出的webpack其实是一个函数,使用方法
webpack({
    // Webpack配置,和webpack.config.js文件一致
}, (err, stats) => {
    if(err || stats.hasErrors()) {
        // 构建过程出错
    }
    // 成功执行完构建
})

如果我们将Webpack配置写在webpack.config.js文件中,如下:

// 读取webpack.config.js文件中的配置
const config = require('./webpack.config.js');
webpack(config, callback);

以监听模式运行

以上使用Webpack API的方法只能执行一次构建,无法以监听模式启动webpack,所以我们要获取Compiler实例以使用API时启动监听模式(关于watchOptions参考

const compiler = webpack(config);
// 调用compiler.watch并以监听模式启动,返回的watching用于关闭监听
const watching = compiler.watch({
    // watchOptions
    aggregateTimeout: 300,
}, (err, stats) => {
    // 每次因文件发生变化而重新执行完构建后
});
// 调用watching.close关闭监听
watching.close(() => {
    // 关闭监听后
})

使用Webpack Dev Middleware

DevServer是一个方便开发的小型HTTP服务,DevServer是基于webpack-dev-middleware和Exressjs实现的,webpack-dev-middleware是Expressjs的一个中间件 看看实现DevServer的大致代码:

const express = require('express');
const webpack = require('webpack');
const webpackMilleware = require('webpack-dev-middleware');
// 从webpack.config.js文件中读取webpack配置
const config = require('./webpack.config.js');
// 实例化一个Expressjs app
const app = express();
// 读取到的webpack配置实例化
const compiler = webpack(config);
// 为app注册webpackMiddleware中间件
app.use(webpackMiddleware(compiler));
// 启动HTTP服务器,服务器监听在3000端口
app.listen(3000)

webpackMiddleware函数返回结果是Expressjs中间件,有以下功能

  • 接收来自webpack compiler实例输出的文件,但是不会将文件输出到磁盘,而是保存在内存中
  • Expressjs app上注册路由,拦截HTTP收到的请求,根据请求路径相应对应的文件内容

Webpack Dev Middleware支持的配置项

Node调用webpac-dev-milldeware提供的api时,可以向它传入一些配置项,方法如下:

// webpackMilddleware函数的第二个参数为配置项
app.use(webpackMiddleware(compiler, {
    // 在webpack-dev-middleware支持的所有配置项中,只有publicPath属性为必填项,其他都是选填
    // webpack输出资源绑定HTTP服务器根目录,和webpack配置中的publicPath含义一致
    pubilcPath: '/assets/',
    // 不输出info类型的日志到控制台,只输出warn和error类型的日志
    noInfo: false,
    // 不输出任何类型的日志到控制台
    quiet: false,
    // 切换到懒惰模式,这意味着不监听文件的变化,只会再有请求时再编译对应的文件,适合页面非常多的项目
    lazy: true,
    // watchOptions
    // 只在非懒惰模式下才有用
    watchOptions: {
        aggregateTimeout: 300,
        poll: true
    },
    // 默认的URL路径,默认时index.html
    index: 'index.html',
    // 自定义HTTP头
    headers: {
        'X-Custom-Header': 'yes'
    },
    // 为特定后缀文件添加HTTP mimeTypes作为文件类型映射表
    mimiTypes: {
        'text/html': ['phtml']
    },
    // 统计信息输出样式
    stats: {
        colors: true
    },
    // 自定义输出日志的展示方法
    reporter: null,
    // 开启或关闭服务器渲染
    serverSideRender: false,
}))

Webpack Dev Middleware与模块热替换

DevServer提供了模块热替换功能,虽然它基于webpack-dev-middleware实现,但是webpack-dev-middleware并没有实现模块热替换功能,DevServer自己实现了该功能 怎么滴才能在使用webpack-dev-middleware时候也能使用模块热替换呢? 1、修改webpack.config.js,加入HotModuleReplacementPlugin:

const HtoModuleReplacementPlugin = require('webpack/HotModuleReplacementPlugin');
module.exports = {
    entry: [
        // 为了支持模块热替换,注入代理客户端
        'webpack-hot-middleware/client',
        // JS执行入口文件
        './src/main.js'
    ],
    output: {
        // 将所有依赖的模块合并输出到一个bundle.js文件
        filename: 'bundle.js',
    },
    plugins: [
        // 为了支持模块热替换,生成.hot-update.json文件
        new HotModuleReplacementPlugin(),
    ]
    devtool: 'source-map',
}

相当于完成webpck-dev-server --hot工作 2、修改HTTP服务器代码的server.js文件,接入webpack-hot-middleware中间件,修改如下:

const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');
// 从webpack.config.js文件中读取webpack配置
const config = require('./webpack.config.js');
// 实例化一个Expressjs app
const app = express();
// 用读取到的Webpack配置实例化一个Compiler
const compiler = webpack(config);
// 为app注册webpackMiddleware 中间件
app.use (webpackMiddleware(compiler));
// 为了支持模块热替换,响应用于替换老模块的资源
pp.use(require('webpack-hot-middleware')(compiler));
// 将项目根目录作为静态资源目录,用于服务HTML文件
app.use (express.static('.')); 
// 启HTTP服务器,服务器监听在3000端口
app.listen(3000, () => {
    console.info('成功监听 3000');
}

3、修改执行入口文件main.js,加入替换逻辑,在文件末尾加入以下代码:

if(module.hot) {
    module.hot.accept()
}

4、安装依赖

npm i -D webpack-dev-middleware webpack-hot-middleware express

安装成功后,通过node ./server.js就能启动一个类似于Dev Server 的支持模块热替换的自定义HTTP服务。