webpack学习笔记:step1 基础用法

194 阅读4分钟

最近在学webpack,我想最好的学习方式还是要有输出才行。嗯,那就写一下博客记录一下学习的过程和收获吧。

核心概念

entry

功能:指定webpack打包的入口
单入口:entry是一个字符串

modules.exports = {
    entry: './src/app.js'
}

多入口: entry是一个对象

modules.exports = {
     entry: {
        app: './src/app.js',
        adminApp: './src/adminApp.js'
     }
 }

output

功能:告诉webpack如何将编译后的结果输出到磁盘 单入口

modules.exports = {
    entry: './src/app.js',
    output: {
       filename: 'bundle.js',
       path: __dirname + '/dist'
    }    
}

多入口

modules.exports = {
    entry: {
        app: './src/app.js',
        adminApp: './src/adminApp.js'
    },
    output: {
       filename: '[name].js', // name对应的是entry的key
       path: __dirname + '/dist'
    }    
}
loader

功能:webpack本身只支持js和json两种文件类型,通过loader把其他文件类型转换成可以添加在视图中的模块。

常见的loader

用法

modules.exports = {
    module: {
        rules: [
            {test: /\.txt$/, use: 'raw-loader'}
        ]
    }
}
plugins

功能:作用于整个构建过程,可以理解为loader不能完成的事情,由plugins完成。 常用的plugins

mode

功能:用来指定当前的构建环境,webpack会根据当前的环境,开启一些配置。 参数:可以设置的值有production, development, none

常用的loader使用说明

用babel-loader配置解析js/jsx

安装babel-loader和核心依赖包

yarn add --dev babel-loader @babel/core @babel/preset-env @babel/preset-react

新建babel配置文件.babelrc 这个文件里面有两个参数,一个是plugins,一个是presents,可以理解为presets里面一个项是一系列plugins的集合,用于实现某个大功能,而plugins里面每个项都只能实现一个小功能。

  {
      "presets": [
          "@babel/preset-env",
          "@babel/preset-react"
      ]
  }

添加babel-loader规则

 module: {
        rules: [
            {
                test: /\.(js|mjs|jsx|ts|tsx)$/,
                use: 'babel-loader'
            }
        ]
 }
            
配置解析css

Loader的调用是链式调用,执行顺序是从右到左,所以在定义css的时候,要先写style-loader,再写css-loader,这样执行的时候,会先执行css-loader然后把执行结果传递给style-loader

yarn add --dev style-loader css-loader
rules: [
 {
	 test: /\.css$/,
	 use: [
		 'style-loader',
		 'css-loader'
	 ]
 }
] 
配置解析sass
yarn add --dev node-sass sass-loader

如果上面配置了css的解析规则,那这里就只需要写一个sass-loader,把sass转换成css,然后会进入css的配置项,用css-loader继续解析。

   {
        test: /.scss$/,
        use: [
            // 如果上面没有定义css解析规则,这里要取消注释
            // style-loader,
            // 'css-loader',
            'sass-loader'
        ]
   }
配置解析图片字体

这里可以用url-loader和file-loader,他们的区别就是url-loader可以把图片转换成base64,而file-loader没有这个功能

{
    test: /.(png|jpg|gif|jpeg)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 10240 // 小于10240就会被转换成base64,也可以用file-loader, file-loader不会转换成base64
            }
        }
    ]
},
{
    test: /.(woff|woff2|eot|ttf|otf)$/,
    use: 'file-loader'
}

webpack的文件监听和热更新

直接使用webpack --watch启动可以实现文件监听,但不能做到热更新。我们可以用webpack-dev-server或者webpack-dev-middleware来实现。

webpack-dev-server

WDS不把构建结果直接输出在磁盘,而是在内存中,所以速度会更快。需要配合webpack.HotModuleReplacementPlugin使用 安装依赖

yarn add --dev webpack-cli webpack-dev-server

配置

const webpack = require("webpack")
modules.exports = {
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        contentBase: './dist',
        hot: true
    }
}
webpack-dev-middleware

需要配合express启动一个服务器,然后把webpack配置的内容传输给服务器。

const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')

const app = express()
const config = require('./webpack.config.js')
const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler, {
  publicPath: config.output.publicPath
}))

app.listen(3000, function() {
  console.log("app started on port 3000)
}

热更新原理: 启动阶段: 1—>2—>A—>B: 编译打包好的文件,经过bundle server,提供给浏览器,让浏览器能够以http://localhost来访问,也就是说bundle server相当于一个文件服务器。在这个阶段同时会把HMR Runtime注入到浏览器中,然后HMR Runtime跟HMR Server建立一个websocket的连接。
更新阶段 1—>2—>3—>4: 修改的文件,经过编译后,传输给HMR Server,然后HMR Server通过websocket把修改的文件传输给HMR Runtime, HMR Runtime会替换bundle.js里面的内容。

文件指纹

概念:就是我们经常看到上线之后的文件名后面加了一段hash的随机数。它用来做版本管理,例如,只更新有修改的文件。另外,对没有修改的文件,浏览器可以直接使用缓存,加速页面的加载速度。
分类:
Hash: 项目文件发生改变,整个项目的hash就会发生改变,所以无法做到一个页面的修改, 只影响它相关的打包出来的js.
Chunkhash: 一个打包出来的文件,实际上就是多个chunk构成的。Chunkhash保证了当A页面的chunk发生改变了,只修改A页面编译出来的文件的文件指纹。
Contenthash: 一个单独的文件对应的hash,只要文件内容发生改变,hash就会跟着改变。 生成:
js: 一般使用chunkhash,也就是当这个js相关的文件发生改变时,才重新生成一个js文件。

 output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name]_[chunkhash:8].js'
},

css: 一般使用contenthash,也就是文件内容发生改变就重新生成一个css文件。如果只使用style-loader,css是作为一个style的标签,插入到html元素中,这个时候是没有独立的css文件的,所以需要配合使用MiniCssExtractPlugin。

module: {
    rules: [
        {
            test: /.scss$/,
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'sass-loader'
            ]
        }
    ]
},
plugins: [
    new MiniCssExtractPlugin({
        filename: '[name]_[contenthash:8].css'
    })
]

图片/文字: 一般使用hash,这里的hash就是contenthash,直接在loader那里配置

{
    test: /.(woff|woff2|eot|ttf|otf)$/,
    use: [
        {
            loader: 'file-loader',
            options: {
               name: '[name]_[hash:8][ext]'
            }
        }
    ]
}

代码压缩

js压缩:使用uglifyjs-webpack-plugin, webpack4内置了uglifyjs, 当mode是production的时候,会默认进行压缩。
css压缩:optimize-css-assets-webpack-plugin,同时使用预处理器cssnano 安装依赖

yarn add --dev cssnano optimize-css-assets-webpack-plugin 

配置

 plugins: [
    new OptimizeCssAssetsWebpackPlugin({
        assetNameRegExp: /\.css$/g,
        cssProcessor: require('cssnano')
    }),
]

Html压缩:使用强大html-webpack-plugin,我们想要生成一个html文件,就要写一个new htmlWebpackPlugin,当然写法可以优化。它最主要的作用是根据模板,编译生成一个html文件,同时把chunk指向的js/css插入到html中。这里主要是通过minify设置压缩模式

    plugins: [
        new htmlWebpackPlugin({
            template: path.join(__dirname, "src/search.html"),
            filename: 'search.html',
            chunk: ['search'],
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            }
        })
    ]

参考来自

极客时间的webpack课程:time.geekbang.org/course/intr…