webpack 简析

528 阅读6分钟

webpack可以做的事:

  • 处理各种资源,css、js、html、图片等
  • 代码转换、文件优化、代码分割、模块合并、自动刷新、代码校验、自动发布

1. 基本使用

1.安装

这里使用webpack4版本

npm install --save-dev webpack webpack-cli

2. 0配置

默认入口是 src 下的 index.js , 出口是 dist 下的main.js

webpack4版本默然打包的是生成环境 production 打包之后文件都是已经压缩

// 运行
npx webpack

3. 手动配置

默认配置文件的名字 webpack.config.js, webpack 是用node写的,所以配置文件要用node的模块化语法

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'build.js', //'打包后模块名称'
        path: path.resolve(__dirname, 'dist'), //'打包后路径,要用绝对路径'
        publicPath: ''
    },
    mode: development, //模式默认两种,一个是生成环境production ,一个是测试环境development
}

1. 入口出口

  • entry 入口文件 这里是单文件,就是项目的入口
  • output 出口文件的配置,包括名字,输入位置,publicPath(打包文件添加的路径,一般是域名来做CDN)

2. resolve webpack启动后会从配置入口模块查找依赖模块,Resolve配置就是告诉webpack如何查找模块对应文件

  • alias
    这个属性非常常用,用来定义别名,在使用的时候可以不用引入特别长的路径,比如
    如果页面中引入 components开头,就是去 'src/components'路径查找

    import button from 'components/button'
    import button from '/src/components/button'
    
    resolve: {
        alias: {
            'components': '/src/components'
        }}
    
  • extensions 
    项目中为了写法简洁引入文件时候经常不加后缀,这个时候webpack会自动加上后缀检查文件是否存在

    import button from 'components/button' // 这里就省略了 .vue扩展
    
    extensions: ['.js', '.vue', '.json'] // 依次按照js, vue, json 添加尾缀然后查找文件
    
  • modules
    modules 会告诉webpack去哪些目录下面查找第三方模块,默认是去node_modules目录下面去找,我一般还会配置上自己的模块库

    modules: ['./src/components', 'node_modules']
    
  • mainFields
    有的文件会根据不同环境提供几份代码,比如分别提供了 ES5 和 ES6两份代码,入口都写在库文件的package.json中

    {
        "next: main": 'es/index.js', // ES6
        "main": 'lib/index.js' // ES5
    }
    

    比如我们想先加载ES6,就要要这样配置

    mainFields: ["next: main", "main"]
    

4. 自定义config文件名

通过config 参数确定配置文件位置

//运行
npx webpack --config webpack.config.test.js // 

或者直接配置到package.json中

scripts: {
    'build': 'webpack --config webpack.config.test.js'
}

运行

npm run build

2. webpack-dev-server web服务器

1. 安装 

npm install --save-dev webpack-dev-server

2. 启动dev-server

npx webpack-dev-server

3. 8080端口静态服务器

但是静态目录不是我们需要的,我们需要的是启动一个把文件打包到内存中的本地服务器

4. devServer配置

{
    devServer: {
        host: '127.0.0.1',
        port: 9999,
        contentBase: './build'
    }
}

其中 contentBase 是服务的的目录位置,host,不配置默认是localhost ,但是不能启动成功,只有配置成 127.0.0.1 才能成功, 服务启动后就会找到 contentBase下面的html 文件

5. 代理

本地启动一个3000的web服务,但是接口在另一台服务器上 比如 4000端口,这个时候就要把接口代理到接口服务器上

devServer: {
    proxy: {
        '/api/': 'http://localhost:4000'
    }
}

上面配置的意思是,只要3000端口访问带 api的资源都会代理到 4000端口上去

3. 常用plugin 

1.html-webpack-plugin

可以将一个模板拷贝到打包后的目录,并把打包后的js插入到模板中,这样的话就不用受到添加html文件了

plugins: [
    new HtmlWebpackPlugin({
        template: '模板文件路径',
        filename: '生成的文件名称'
    })
]

还可以压缩生成的html

new HtmlWebpackPlugin({
    minify: {
        collapseWhitespace: true, // 去掉空格
    }
})

2. clean-webpack-plugin

主要用途就是将打包后的目标文件先删除,然后再打包,

let { CleanWebpackPlugin } = require('clean-webpack-plugin')
new CleanWebpackPlugin({
    root: path.resolve(__dirname, 'build')
})

3. copy-webpack-plugin

主要用途会把一些静态资源复制到打包好的目录中

let CopyWebpackPlugin = require('copy-webpack-plugin')
new CopyWebpackPlugin([
    {
        from: '静态文件目录',
        to: '打包后的目录'
    }
])

4. DefinePlugin

这是webpack 自带的插件,用来定义变量,主要用来区分 生产环境和 dev环境

new webpack.DefinePlugin({
    "process.env": {
        'NODE_ENV': 'development' // 这的赋值可以是development 或者 production
    }
})

页面中使用, 直接使用 process.env来区分环境

process.env.NODE_ENV == 'development'

4.常用loader

下面我们针对页面中这些资源  CSS, JS, 全局变量,文件 看看哪些loader可以处理以上资源

1. css-loader

css-loader 是用来解析@import 和 url的,当我们在index.js 中引入一个css文件

// index.js
import css from './style.css'
console.log(css)

// style.css
body{
    background: red;
}

webpack 中loader 配置, 所有的loader 规则写在module 对象的 rules 里面,rules对象是个数组,接收多个规则,规则解析从后向前

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

启动dev-server服务看到 index.js 中的 css解析出来是一个数组,第一个元素是 路径和解析出来的样式字符串

css-loader只会把css模块加载到JS代码中

2. style-loader

这样就解析了css 但是这个时候页面还没生效,也就是说没有把解析好的css 插入到页面中,这个时候就需要style-loader, style-loader 会把 css-loader生成的数组样式,解析后生成style 标签插入到head 中,这样样式就生效了

修改一下上面css-loader 代码, rules 中  use 是个数组,元素可以是对象,也可以是字符串loader名称 如: use: ['style-loader', 'css-loader'], 规则都是从右向左

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

这个时候页面中head 中就有了 样式了

3. less-loader

主要作用是将less 语法转换成css语法, 需要安装less-loader 和 less 模块 ,less-loader会调用less的render方法,后面手写的时候会提到

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

4. postcss-loader

以前浏览器兼容,会对不同浏览器加不同前缀,这就导致写了若干兼容代码

postcss 是什么:我们可以理解它为css的编译工具,类似于babel对js的处理,他提供CSS解析器,将CSS解析成抽象语法数(AST),虽然本身对CSS不会处理什么,但是通过插件就可以实现对CSS的操作,

常用的 autoprefixer,  实现css3代码自动补全

postcss-loader用法, 这里注意postcss 已经要放到 css 之前处理(从右到左)

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

这里还要添加一个 postcss.config.js

var autoprefixer = require('autoprefixer')
module.exports = {
    plugins: [ autoprefixer ]
}

这样对元素添加一个 transform: rotate(45deg), 就看到了添加的前缀

5. babel-loader

上面介绍了一些处理css的loader ,这里说下处理js的loader, 一般都是将高级别的语法转换成浏览器能识别的ES5语法, 这里babel本身不转义代码,如果没有插件,babel处理之后代码不会有变化

安装 

这里需要安装 babel-loader @babel/core( 转换成语法数) @babel/preset-env(可以看做是babel的插件,转义的语法规则)

module: {
    rules: [
        { test: /\.js$/, loader: 'babel-loader'}
    ]
}

所有要添加引入的插件文件 .babelrc, 这里的转义规则可以根据需要自行配置,

我常用的就是stage-2, 

还有一些插件 transform-runtime 等(generator语法),

还有一些实例的方法不能使用 比如数组 includes 方法 可以用babel-polyfill

{
    persets: ['@babel/preset-env']}

6. expose-loader

为了解决一些插件不支持CommonJs引入问题,比如 bootstrap.js,只能jquery 暴露全局变量才可以用,所有会有需求把第三方库暴露成全局变量

首先webpack 配置, 这里要注意,不用版本写法不同,支持的webpack也不同

rules: {
    test: require.resolve('jquery'),
    loader: 'expose-loader',
    exposes: ['$', 'jQuery']
}

然后文件中使用require才会生效, 这个时候$和 jQuery 会挂载到window下面

require('jquery')

1另外还有一些其他方法可以暴露全局变量,webpack的 externals 属性,webpack的ProvidePlugin插件, 可以直接将jquery暴露到全局变量中,不需要再require引入了

7. file-loader

主要处理一些引入的资源,图片,字体,图标等, 将处理的图片打包到对应的目录下面

rules: [
    { test: /\.(png|jpg\gif)$/, loader: 'file-loader' }
]

这个时候看打包好的文件目录就会有一个名字为hash码前缀的图片资源

8. url-loader

这个也是处理项目中引入的图片等资源,与 file-loader不同的是,一般处理小尺寸的图片,直接生成base64,这样页面就不用再请求图片资源了,直接加载出来图片,但是base 64 一般比打包前的图片大, 一般会做配置 limit 超过多少k的图片就 用file-loader 打包,小于就用url-loader生成base 64

rules: [
    { test: /\.(png|jpg|gif)$/, loader: 'url-loader', options: {
        limit: 200 * 1024
    }}
]

5.Source Map

当正式环境打包后,会压缩代码,可能代码就会一行显示,当代码中报出错误,由于一行显示代码不能找到错误的具体位置,source map就是做了映射,更有利于调试

module.exports = {
    devtool: '配置项'
}

下面是不同配置项对应的结果

  1. source-map: 源码映射,功能最全,打包速度会变慢, 会单独生成一个.map 文件
  2. eval-source-map:  直接在源码中写入source-map,不影响构建速度,单影响执行速度
  3. cheap-module-source-map: 会产生一个不带映射的单独的map文件,开发中工具可以看到,看是不能对应到对应的列
  4. cheap-module-eval-source-map: 不单独生成map文件,但是开发者工具可以看到行,不能对应的列

6.结束

本篇主要简单介绍了webpack 一些常用的插件和 用法,后续还有优化和手写loader和plugin以及源码的实现的文章,不温不火更新中....,欢迎关注