资讯专栏INFORMATION COLUMN

webpack学习笔记(3)-webpack使用

wwq0327 / 1496人阅读

摘要:配置如上图测试用例所示,由于这个插件默认使用了来作优化,所以它不仅压缩了代码删掉了代码中无用的注释还去除了冗余的优化了的书写顺序,优化了你的代码。

webpack基本使用
// webpack4中除了正常安装webpack之外,需要再多带带安一个webpack-cli

npm i webpack webpack-cli -D
基本命令行

webpack []

配置文件使用

直接输入webpack,默认执行: webpack.config.js or webpackfile.js文件;
如果想自定义文件名,运行:webpack --config webpack.conf.dev.js

打包js
// ESmodule
export default function(a,b){
    return a+b
}
import sum from "./sum"

// common.js规范

module.exports = function(a,b){
    return a-b
}
var minus = require("./minus")

// AMD规范,多了两个bundle,异步加载
//amd规范
define(function(require, factory) {
    "use strict";
    return function(a,b){
        return a*b
    }
});

require(["./muti"],function(muti){
    console.log("muti,23,24="+muti(23,24))
})
console.log("sum,23,24="+sum(23,24))
console.log("minus,23,24="+minus(23,24))
编译 ES 6/7

安装babel-loader, babel-core, babel-preset-env

npm install --save-dev babel-loader babel-core babel-preset-env

babel-loader:在import或加载模块时,对es6代码进行预处理,es6语法转化为es5语法。
babel-core:允许我们去调用babel的api,可以将js代码分析成ast(抽象语法树),方便各个插件分析语法进行相应的处理.
babel-preset-env:为了告诉babel只编译批准的内容,相当于babel-preset-es2015, es2016, es2017及最新版本。通过它可以使用最新的js语法。

配置webpack.config.js

module.exports = {
    entry:{
        app:"./app.js"
    },
    output:{
        filename:"[name].[hash:5].js"
    },
    module:{
        rules:[
            {
                test:/.js$/,
                use:{
                    loader:"babel-loader",
                    options:{
                        presets:[
                            // 最新的版本
                            ["@babel/preset-env",{ 
                                targets:{// 支持目标,数据来源于‘can i use’网站
                                    browsers:["> 1%","last 2 versions"]
                                    //chrome:"52"
                                }
                            }]
                        ]
                    }
                },
                //排除相关文件
                exclude:"/node_modules/"
            }
        ]
    }
}

其中,exclude是定义不希望babel处理的文件。targets是presets的一些预设选项,这里表示将js用于浏览器,只确保占比大于1%的浏览器的特性,主流浏览器的最新两个主版本。
更多与配置有关的信息,可以参考:
babel env preset设置,
browserlist预设置

由于babel-preset配置选项较多,我们一般可以在根目录下建立.babelrc文件,专门用来放置babel preset配置,这是一个json文件。可以将上述配置修改如下:

//.bablerc文件
{
    "presets": [
        ["env",{
            "targets": {
                "browsers": ["> 1%", "last 2 versions"]
            }
        }]
    ]
}

//原webpack.config.js文件
module: {
    rules: [
        {
            test: /.js$/,
            use: {
                loader: "babel-loader"
            },
            exclude: "/node_modules/"
        }
    ]
}
babel-polifill

在上面的babel配置中,babel只是将一些es6,es7-8的语法转换成符合目标的js代码,但是如果我们使用一些特性或方法,比如Generator, Set, 或者一些方法。babel并不能转换为低版本浏览器识别的代码。这时就需要babel-polifill。

简单的说,polifill就是一个垫片,提供了一些低版本es标准对高级特性的实现。使用polifill的方法如下:

npm install --save babel-polifill

然后在应用入口引入polifill,要确保它在任何其他代码/依赖声明前被调用。

//CommonJS module
require("babel-polyfill");

//es module
import "babel-polifill";

在webpack.config.js中,将babel-polifill加入entry数组中:

entry: ["babel-polifill", "./app.js"]

相比于runtime-transform,polifill用于应用开发中。会添加相应变量到全局,所以会污染全局变量。
更多配置参考:babel-polifill

完整代码如下:

const path = require("path");
module.exports = {
    //entry为入口,webpack从这里开始编译
    entry: [
        "babel-polyfill",
        path.join(__dirname, "./src/index.js")
    ],
    //output为输出 path代表路径 filename代表文件名称
    output: {
        path: path.join(__dirname, "./bundle"),
        filename: "bundle.js"
    },
    //module是配置所有模块要经过什么处理
    //test:处理什么类型的文件,use:用什么,include:处理这里的,exclude:不处理这里的
    module: {
        rules: [
            {
                test: /.js$/,
                use: ["babel-loader"],
                include: path.join(__dirname , "src"),
                exclude: /node_modules/
            }
        ]
    },
};
runtime-transform插件

runtime transform也是一个插件,它与polifill有些类似,但它不污染全局变量,所以经常用于框架开发。
安装:
*npm install --save-dev babel-plugin-transform-runtime

npm install --save babel-runtime*
用法:
将下面内容添加到.bablerc文件中

{
    "plugins": ["transform-runtime"]
}

更多配置参考:bable-runtime-transform插件

使用 loader 处理 CSS

1 . 安装处理 css 相关 loader

// css-loader让你能import css  , style-loader能将css以style的形式插入
$ npm install --save-dev css-loader style-loader
module.exports = {
    plugins: [require("autoprefixer")]  // 引用该插件即可了
}

然后在webpack里配置postcss-loader

module.exports = {
    module: {
        rules: [
            {
                test: /.css$/,
                use: ["style-loader", "css-loader", "postcss-loader"]
            }
        ]
    }
}

2 . 安装 less 相关

npm install --save-dev less less-loader

3 . 添加CSS3前缀
通过postcss中的autoprefixer可以实现将CSS3中的一些需要兼容写法的属性添加响应的前缀,这样省去我们不少的时间

npm i postcss-loader autoprefixer -D

创建 postcss.config.js 加入以下代码

module.exports = {
    plugins: {
        "postcss-cssnext": {}
    }
}

4 . 实现

src/app.css

body {
  background: pink;
}

src/app.js

import css from "./app.css";

console.log("hello world");
// 处理顺序从右到左 less -> postcss -> css -> style
        {
           test: /.css$/,
           use: [ "style-loader", "css-loader" ]
        }

5.用 mini-css-extract-plugin 把 CSS 分离成文件

npm install --save-dev mini-css-extract-plugin
    rules: [
            {
                test: /.css$/,
                use: [MiniCssExtractPlugin.loader, "css-loader"]
            }
    ]


 new MiniCssExtractPlugin({
        filename: "[name].css",// 指定打包后的css
        chunkFilename: "[id].css"
 }),

6.压缩与优化
打包 css 之后查看源码,我们发现它并没有帮我们做代码压缩,这时候需要使用 optimize-css-assets-webpack-plugin 这个插件,它不仅能帮你压缩 css 还能优化你的代码。

npm install --save-dev optimize-css-assets-webpack-plugin
const optimizeCss = require("optimize-css-assets-webpack-plugin");
//配置
optimization: {
  minimizer: [new OptimizeCSSAssetsPlugin()];
}

如上图测试用例所示,由于optimize-css-assets-webpack-plugin这个插件默认使用了 cssnano 来作 css 优化,
所以它不仅压缩了代码、删掉了代码中无用的注释、还去除了冗余的 css、优化了 css 的书写顺序,优化了你的代码 margin: 10px 20px 10px 20px; =>margin:10px 20px;。同时大大减小了你 css 的文件大小。更多优化的细节见文档。

插件 生成HTML插件

安装插件npm install --save-dev html-webpack-plugin 配置 webpack.config.js

npm install --save-dev html-webpack-plugin
const htmlWebpackPlugin = require("html-webpack-plugin");
...
plugins: [
    new htmlWebpackPlugin({
        filename: "index.html",  //打包后的文件名
        template: path.join(__dirname , "./src/index.html"),  // 用哪个html作为模板,在src目录下创建一个index.html页面当做模板来用
        hash: true, // 会在打包好的bundle.js后面加上hash串
    })
],

如果需要多页面开发,可以这样写:

let path = require("path");
let HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    // 多页面开发,怎么配置多页面
    entry: {
        index: "./src/index.js",
        login: "./src/login.js"
    },
    // 出口文件  
    output: {                       
        filename: "[name].js",
        path: path.resolve("dist")
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html",   
            filename: "index.html",
            chunks: ["index"]   // 对应关系,index.js对应的是index.html
        }),
        new HtmlWebpackPlugin({
            template: "./src/login.html",
            filename: "login.html",
            chunks: ["login"]   // 对应关系,login.js对应的是login.html
        })
    ]
}

html-webpack-plugin用法全解

清理打包文件插件
$ npm i clean-webpack-plugin --save-dev
const CleanWebpackPlugin = require("clean-webpack-plugin");
...
plugins: [
    ...
    new CleanWebpackPlugin(["bundle"]) //传入清楚路径
]
提取公共代码 原因和优势

原因
1.相同的资源被重复的加载,浪费用户的流量和服务器的成本;
2.每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验。

优点
1.减少网络传输流量,降低服务器成本;
2.虽然用户第一次打开网站的速度得不到优化,但之后访问其它页面的速度将大大提升。

optimization

在webpack4之前,提取公共代码都是通过一个叫CommonsChunkPlugin的插件来办到的。到了4以后,内置了一个一模一样的功能,而且起了一个好听的名字叫“优化”

下面我们就来看看如何提取公共代码

// 假设a.js和b.js都同时引入了jquery.js和一个写好的utils.js
// a.js和b.js
import $ from "jquery";
import {sum} from "utils";

那么他们两个js中其中公共部分的代码就是jquery和utils里的代码了

可以针对第三方插件和写好的公共文件

module.exports = {
    entry: {
        a: "./src/a.js",
        b: "./src/b.js"
    },
    output: {
        filename: "[name].js",
        path: path.resolve("dust")
    },
    // 提取公共代码
+   optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {   // 抽离第三方插件
                    test: /node_modules/,   // 指定是node_modules下的第三方包
                    chunks: "initial",
                    name: "vendor",  // 打包后的文件名,任意命名    
                    // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
                    priority: 10    
                },
                utils: { // 抽离自己写的公共代码,utils这个名字可以随意起
                    chunks: "initial",
                    name: "utils",  // 任意命名
                    minSize: 0    // 只要超出0字节就生成一个新包
                }
            }
        }
+   },
    plugins: [
        new HtmlWebpackPlugin({
            filename: "a.html",
            template: "./src/index.html",  // 以index.html为模板
+           chunks: ["vendor", "a"]
        }),
        new HtmlWebpackPlugin({
            filename: "b.html",
            template: "./src/index.html",  // 以index.html为模板
+           chunks: ["vendor", "b"]
        })
    ]
}

通过以上配置,可以把引入到a.js和b.js中的这部分公共代码提取出来,如下图所示

webpack-dev-server配置

安装 webpack-dev-server

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

webpack.config.js 添加配置

...
devServer: {
    contentBase: path.join(__dirname, "bundle"),  //启动路径
    host:"localhost",  //域名,默认是localhost
    port: 8018,  //端口号
    open: true, //自动打开浏览器
    hot: true //开启热更新
}

当然在npm run dev命令下,打包的文件存在于内存中,并不会产生在dist目录下

热更新和自动刷新的区别

配置devServer的时候,如果hot为true,就代表开启了热更新

But这并没那么简单,因为热更新还需要配置一个webpack自带的插件并且还要在主要js文件里检查是否有module.hot

下面就让我们直接看下代码是如何实现的

// webpack.config.js
let webpack = require("webpack");

module.exports = {
    plugins: [
        // 热更新,热更新不是刷新
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        contentBase: "./dist",
        hot: true,
        port: 3000
    }
}

// 此时还没完虽然配置了插件和开启了热更新,但实际上并不会生效

// index.js
let a = "hello world";
document.body.innerHTML = a;
console.log("这是webpack打包的入口文件");

// 还需要在主要的js文件里写入下面这段代码
if (module.hot) {
    // 实现热更新
    module.hot.accept();
}
编译图片

file-loader
对一些对象作为文件来处理,然后可以返回它的URL。

$ npm install --save-dev file-loader
test: /.(gif|png|jpe?g|svg)$/i,
use: [
  {
    loader: "file-loader",
    options: { 
      name: "[name].[ext]", // 文件名和扩展名
      outputPath: "images/"
    }
  },

url-loader

npm i file-loader url-loader -D
module.exports = {
    module: {
        rules: [
            {
                test: /.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    use: "css-loader",
                    publicPath: "../"
                })
            },
            {
                test: /.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: "url-loader",
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: "images/"   // 图片打包后存放的目录
                        }
                    }
                ]
            }
        ]
    }
}

解析 html 代码里面 img 的标签

html-loader: html 变成导出成字符串的过程中,还能进行压缩处理(minimized)

$ npm install --save-dev html-loader
...
{
  test: /.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: "file-loader",
      options: {
        name: "[name].[ext]",
        outputPath: "images/"
      }
    },
  ]
},
// 下面几行才是 html-loader 的配置内容
{
  test: /.html$/,
  use: [ {
    loader: "html-loader",
    options: {
      minimize: true
    }
  }],
}
...

压缩图片

image-webpack-loader:压缩图片文件

$  npm install image-webpack-loader --save-dev
{
  test: /.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: "file-loader",
      options: {
        name: "[name].[ext]",
        outputPath: "images/"
      }
    },
    {
      loader: "image-webpack-loader",
      options: {
        bypassOnDebug: true,
      }
    }
  ]
},
{
  test: /.html$/,
  use: [ {
    loader: "html-loader",
    options: {
      minimize: true
    }
  }],
}
resolve解析

在webpack的配置中,resolve我们常用来配置别名和省略后缀名

module.exports = {
    resolve: {
        // 别名
        alias: {
            $: "./src/jquery.js"
        },
        // 省略后缀
        extensions: [".js", ".json", ".css"]
    },
}
打包速度

webpack 4 在项目中实际测了下,普遍能提高 20%~30%的打包速度。

首先你需要知道你目前打包慢,是慢在哪里。

我们可以用 speed-measure-webpack-plugin 这个插件,它能监控 webpack 每一步操作的耗时。如下图:

可以看出其实大部分打包花费的时间是在Uglifyjs压缩代码。和前面的提升热更新的切入点差不多,查看source map的正确与否,exclude/include的正确使用等等。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97110.html

相关文章

  • webpack 学习笔记(一)

    摘要:引言最近在学习,发现好多知识点,之前一点都没有接触过,如等等。使用本地安装,会存于文件夹内与属性内,更方便项目文件迁移以及协同开发等情况。 引言 最近在学习webpack,发现好多知识点,之前一点都没有接触过,如babel、core-js、browserslist等等。以前习惯了使用cli构建项目,很多东西不用考虑,拿来就用,这样的码农是不会有能力提升的,必须了解更多的知识点,才能成为...

    zhangwang 评论0 收藏0
  • webpack学习笔记

    摘要:运行该语句会执行如下步骤使用进行文件压缩。设置环境变量,触发某些包,以不同的方式进行编译。在原始的源码中执行查找和替换操作。等同于表示任何出现的地方都会被替换为。提供函数用来合并配置对象当文件小于限制,会返回。 选项 1.devtool:通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试。 2.resolve.alias:创建 impor...

    Soarkey 评论0 收藏0
  • React学习笔记1:环境搭建

    摘要:新搭建的个人博客,本文地址学习笔记环境搭建本文的书写环境为,之后会补充下的差异创建学习目录初始化项目根据相关提示完善信息,入口文件安装相关包,并且使用也就是支持,需要包,因为我之前做个一些相关项目,所以部分包已经全局安装,比如等等,大家 新搭建的个人博客,本文地址:React学习笔记1:环境搭建 本文的书写环境为mac,之后会补充windows下的差异 1、创建学习目录 mkdir l...

    Sourcelink 评论0 收藏0
  • 我的webpack学习笔记(一)

    摘要:前言在上一篇文章中我介绍了学习前的准备工作,下面开始的学习。目标一般我们接触到的关于的文章,都是以解读官方文档为主,而且是针对单页面项目的应用。我先在假设要做一个多页面应用,该如何去通过打包。 前言 在上一篇文章中我介绍了学习webpack前的准备工作,下面开始webpack的学习。 *创建webpack-demo文件夹 $ mkdir webpack-demo $ cd webpac...

    wh469012917 评论0 收藏0
  • 我的webpack学习笔记(一)

    摘要:前言在上一篇文章中我介绍了学习前的准备工作,下面开始的学习。目标一般我们接触到的关于的文章,都是以解读官方文档为主,而且是针对单页面项目的应用。我先在假设要做一个多页面应用,该如何去通过打包。 前言 在上一篇文章中我介绍了学习webpack前的准备工作,下面开始webpack的学习。 *创建webpack-demo文件夹 $ mkdir webpack-demo $ cd webpac...

    CrazyCodes 评论0 收藏0

发表评论

0条评论

wwq0327

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<