webpack

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

  • 一些准备
    全局安装webpack:npm install -g webpack
    安装完webpack,命令行执行webpack会报错,这是因为webpack4把命令行工具抽离成了独立的包,webpack-cli,所以还需要安装webpack-cli才能使用webpack命令
    安装webpack-cli或webpack-command:npm install -g webpack-clinpm install -g webpack-command
    查看webpack版本:webpack -v
$ webpack -v
webpack: 5.70.0
webpack-cli: 4.9.2
webpack-dev-server not installed
  • 初始化项目:
mkdir test_webpack
cd test_webpack
npm init

开发环境安装webpack以及webpack-cli或webpack-command的依赖
npm install --save-dev webpack
npm install --save-dev webpack-clinpm install --save-dev webpack-command

项目下新建src文件夹,新建入口文件app.js,页面文件work.js
项目下新建index.html
项目下新建webpack.config.js,webpack的一些配置写在这里

app.js

var dt = require('./work.js')

work.js

document.write('test-webpack')

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"> 
        <title>test</title> 
    </head>
    <body> 
        <div>test</div> 
        <script src='./dist/bundle.js'></script> 
    </body> 
</html>

webpack.config.js

  • cache: true 开启缓存功能,只有变化的文件才会重新加载,可提升构建速度
  • entry:
    单入口:value为相对路径,路径可以为数组(在你想要一次注入多个依赖文件,并且将它们的依赖关系绘制在一个 "chunk" 中时,这种方式就很有用。),这时要注意主入口在最后。简写为
module.exports = {
  entry: './path/to/my/entry/file.js',
};
module.exports = {
  entry: ['./src/file_1.js', './src/file_2.js'],
  output: {
    filename: 'bundle.js',
  },
};

多入口:有几个入口,webpack就会打几个包(bundle)出来,打出来的包的文件名与key对应。

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

对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。
有以下几个属性

  • dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。

  • filename: 指定要输出的文件名称。

  • import: 启动时需加载的模块。

  • library: 指定 library 选项,为当前 entry 构建一个 library。

  • runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。
    注意:
    1)runtime 和 dependOn 不应在同一个入口上同时使用,配置无效,并且会抛出错误

module.exports = {
  entry: {
    a2: './a',
    b2: {
      runtime: 'x2',
      dependOn: 'a2',
      import: './b',
    },
  },
};

2)runtime 不能指向已存在的入口名称,会抛出错误

module.exports = {
  entry: {
    a1: './a',
    b1: {
      runtime: 'a1',
      import: './b',
    },
  },
};

3)dependOn 不能是循环引用的,会出现错误

module.exports = {
  entry: {
    a3: {
      import: './a',
      dependOn: 'b3',
    },
    b3: {
      import: './b',
      dependOn: 'a3',
    },
  },
};
  • publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。

  • output:打包之后存放的文件路径。即使可以存在多个 entry 起点,但只能指定一个 output配置。

module.exports = {
  output: {
    filename: 'bundle.js',
  },
};

path 必须是绝对路径,打包后的文件存放的地方, 常取值为:
__dirname+’/build’或path.resolve(__dirname,’build’)(__dirname是node.js里的一个全局变量,它指向的是我们项目的根目录),
filename 为打包后的文件名。对于单入口文件,可以取一个固定的名字,如’build.js’,对于多入口文件,要使用[name].bundle.js或[id].bundle.js来对应,其中name和id是根据多入口文件对象的属性动态确定的
publicPath
规定线上地址,打包后的文件中资源的引用地址会根据这个地址而改变,一般取为’/assets/’
chunkFilename
webpack可以做代码分割,这个属性规定那些做了代码分割的块(chunk)的名字
默认使用 [id].js

const path = require('path');
const webpack = require('webpack'); 
module.exports = { 
    entry:{
        app:__dirname+'/src/app.js',
    },
    output:{
        path: path.resolve(__dirname, './dist'),
        filename:'bundle.js' 
    }
};
// 写入到硬盘:./dist/app.js, ./dist/search.js

多入口的output,name与entry的key相对应

module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js',
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist',
  },
};

package.json

{
  "name": "test_webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack",
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.70.0",
    "webpack-cli": "^4.9.2"
  }
}

执行npm start打包,或webpack 生成dist文件夹下bundle.js

--mode 区分环境,有两周可选的模式,
npm run dev 开发环境,命令为 webpack --mode = development
npm run build 生产环境,命令为webpack --mode = production
开发环境打包出来的文件未经过压缩,而生产环境打包出来的文件是经过压缩的。

image.png

image.png

可见,生产环境的打包出来的文件bundle.js是188bytes,而开发环境是2.43KiB,生产环境会做一些压缩以提高性能。

查看页面,地址栏输入index.html的路径file:///C:/Users/xxxx/workspace/test_webpack/index.html


image.png
  • module:
    • rules 数组,配置编译规则,
      test 正则匹配,exclude 排除特定条件,use-loader,test 匹配到的解析器模块,use-options,与use-loader配合使用。
      有时还会有query或options配置,二者都是use:{options}的简写,所以在用了use后就不需要这两个配置了,如下(一个loader对应一个options,使用多个loader时用use):
use: [
  {
    loader: 'style-loader'
  },
  {
    loader: 'css-loader',
    options: {
      importLoaders: 1
    }
  },
  {
    loader: 'less-loader',
    options: {
      noIeCompat: true
    }
  }
]
  • noParser
    防止 webpack 解析任何与给定正则表达式相匹配的文件,忽略大型库文件(library)可以提高构建性能
noParse: /jquery|lodash/
  • plugins:插件。plugins 与 loader 的区别在于,loader 只是一个解析模块,比如将 ES5 解析成 ES6,LESS 文件解析成 CSS 文件,为了兼容浏览器。而 plugins 是将 loader 之后的文件进行优化分类、压缩、提供公共代码等。

  • devServer:服务器配置,contentBase 文件路径,compress 是否启动 gzip 压缩,host 主机地址,port 端口号,publicPath。

  • loader
    loader 用于对模块的源代码进行转换。webpack只能处理javascript模块,处理其他类型的文件需要loader进行转换。
    像处理css文件 需要css-loader和style-loader,
    css-loader:遍历css文件找到url()表达式然后处理他们
    style-loader:将css代码插入到一个页面中的style标签中
    处理ts文件,需要ts-loader将TypeScript 转为 JavaScript
    安装css-loader和style-loader:npm install css-loader style-loader
    安装ts-loadernpm install ts-loader
    注意:loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。

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

1)loader 支持链式调用。
2)loader 可以是同步的,也可以是异步的。
3)loader 运行在 Node.js 中,并且能够执行任何操作。
4)loader 可以通过 options 对象配置。
5)除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块。
6)插件(plugin)可以为 loader 带来更多特性。
7)loader 能够产生额外的任意文件。

  • 常用plugin:
  1. extract-text-webpack-plugin 与 mini-css-extract-plugin
    分离 .css 分解,后者需要 webpack 4.2.0 版本以上。
  2. UglifyJsPlugin
    压缩 js 文件,减小 js 文件。
  3. html-webpack-plugin 与 html-loader
    生成 html 文件。
  4. clean-webpack-plugin
    每次构建之前清理历史打包文件。

CommonsChunkPlugin
DefinePlugin
HtmlWebpackPlugin
UglifyjsWebpackPlugin
ExtractTextWebpackPlugin
OptimizeCSSPlugin
CompressionWebpackPlugin
SourceMapDevToolPlugin
FriendlyErrorsPlugin
BundleAnalyzerPlugin

  • resolve
    配置模块如何解析
    • root:字符串或值为字符串的数组,绝对路径,配置alias中依赖项的基地址
    • alias
      创建 import 或 require 的别名,来确保模块引入变得更简单。
      对象,key为变量名,值为路径。key指定的变量将成为全局变量,比如想在任何文件中都是用jquery而不必每次都显示引入,可以这样{$:jquery文件的地址},地址可以是相对地址(相对root指定),也可是绝对地址(使用path.resolve(__dirname,’jquery’)).
    • extensions:数组,文件扩展名,某文件的扩展名在该数组中时,该文件在引入时可省略扩展名,常取值有[‘’ , ’.js’ , ‘.json’ , ‘.scss’ , ‘.vue’]
    • modules
      告诉 webpack 解析模块时应该搜索的目录
resolve: {
    extensions: ['.js', '.vue', '.json'],
    modules: [
      resolve('src'),     //实际返回了src的路径,会优先于node_modules搜索
      resolve('node_modules')
    ],
    alias: {
      'vue$': 'vue/dist/vue.common.js',
      '@': resolve('src'),
      'src': resolve('src'),
      'assets': resolve('src/assets'),
      'components': resolve('src/components'),
      'styles': resolve('src/styles'),
      'utils':resolve('src/utils'),
      'demos':resolve('src/demos'),
      'cnode':resolve('src/cnode')
    }
  }
  • externals
    提供了不从 bundle 中引用依赖的方式。也就是所创建的 bundle 依赖于那些存在于用户环境(consumer environment)中的依赖。比如jquery是用script的方式从html引入的,要想在其他模块中引入的时候就可以使用这个配置
// html
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
// 配置
externals: {
  $: 'jQuery'            //key不加引号,value是脚本里的全局对象,这里value还可以是数组或对象,但表示的含义大不一样,可参看[这里](http://www.css88.com/doc/webpack2/configuration/externals/)
}
// 其他模块引入的方式
import $ from 'jquery';
  • performance、stat
    performance:某个打包后的包超过给定阈值时给出提示
    stat: 控制webpack打包后输出哪些信息

package.json

const path = require('path');
const webpack = require('webpack'); 
module.exports = { 
    entry:{
        app:__dirname+'/src/app.js',
    },
    output:{
        path: path.resolve(__dirname, './dist'),
        filename:'bundle.js'
    },
    // module: {
    //     loaders:[
    //         {test: /\.css$/, loader: "style-loader!css-loader"}
    //     ],
    //     plugin: [
    //         new webpack.BannerPlugin('webpack 实例')
    //     ]
    // }
    module:{
        rules:[
              {
                test: /\.js$/,
                loader: 'babel-loader?cacheDirectory=true',
                include: [
                  resolve('src'),
                ],
                exclude:path.resolve(__dirname, 'node_modules')
             },
            {
                test:/\.css$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'postcss-loader'

                ]
            },{
                test:/\.(png|svg|jpg|gif)$/,
                loader: 'url-loader',
                options: {
                  limit: 10000,
                  name: utils.assetsPath('img/[name].[hash:7].[ext]')
                }
            }
        ]
    }
};

安装webpack-dev-server:npm install webpack-dev-server -g
打开localhost:8080

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容