webpack bundleloader生成bundle.js文件为什么那么大,会影响加载速度吗

易懂的 webpack 使用教程 - 掘金
阅读 2830收藏 145原文链接:对于初学者来说是一篇易懂的 webpack 使用教程。 —— 由
我最近大量使用 ,但因为它搭建的环境里,测试代码不好写,而项目又有写测试的计划,所以决定改用 。
我还记得我刚接触 webpack 时的心情:零零碎碎。
就没个简单、现成、完整的方案?我是说,我真的不太关心 js 文件要配什么加载器。我只想快一点把开发环境搭起来好干活。总之,几经折腾,我嫌麻烦放弃了 webpack 这个方案。
但今天回头去看,其实它并没那么复杂。
那么,webpack 是什么?
MODULE BUNDLER
它是这么自称的,模块打包器。
在 webpack 里,所有类型的文件都可以是模块,包含我们最常见的 JavaScript,以及 css 文件、图片、json 文件等等。通过 webpack 的各种加载器,我们可以更有效地管理这些文件。
起手式 – 安装 webpack
我们通过 npm 全局安装 webpack:
npm install webpack -g
安装完成后,我们可以使用 webpack 命令,执行
webpack --help
能够查看 webpack 提供的所有命令。
不过,通常建议在项目目录中安装一份本地的 webpack:
npm install webpack --save-dev
如果觉得 npm 安装太慢,可以尝试 npm 的替代工具
– 我的使用经历,它的速度比 npm 快太多了。
初始化项目
安装好 webpack 后,我们要怎么开始一个项目?
如果你用过 grunt.js、gulpjs 一类工具,它们可以借助 。webpack 的情况不太一样,我们可以把它当作 node.js 项目来初始化。当然,借用一些模板会更省事,比如 。
但这里还是聊聊如何手动初始化一个 webpack 项目。
创建一个 package.json 文件,用于保存项目版本、依赖关系等
在当前目录下安装 webpack
npm install webpack --save-dev
之后,我们的项目下有两个内容:
package.json 文件
node_modules 文件夹
我们还需要一个 index.html 文件,示例如下:
&!DOCTYPE html&
&html lang=&en&&
&meta charset=&UTF-8&&
&title&webpack 教程&/title&
现在,我们可以通过
等访问到 index.html 页面。
目前页面上还是一片空白,除了一个标题。
webpack 配置
在单页面应用里,项目通常会有一个入口(entry)文件,假设是 main.js,我们通过配置 webpack 来指明它的位置。
首先,在项目根目录新建一个 webpack.config.js,这是 webpack 默认的配置文件名称,添加以下内容:
module.exports = {
entry: './main.js'
这时在项目根目录执行 webpack,会提示我们,
Output filename not configured.
因为我们只是设定了入口(entry),还没有设定一个输出文件的路径与名称。
在 webpack.config.js 中添加一个 output:
module.exports = {
entry: './main.js',
path: __dirname, // 输出文件的保存路径
filename: 'bundle.js' // 输出文件的名称
现在在项目里执行 webpack 命令,我们的根目录下会多出一个 bundle.js 文件:
接下来,在 index.html 中引用 bundle.js 文件:
&!DOCTYPE html&
&html lang=&en&&
&meta charset=&UTF-8&&
&title&webpack 教程&/title&
&script src=&./bundle.js&&&/script& &!-- 在 index.html 文件中添加这一行代码 --&
大功告成。
这是 webpack 与 browserify 一类工具的特点,它们在 HTML 文件中直接引用构建后的 js 文件,而不是源文件。
当然,这可能会引发性能问题,毕竟,如果每一点文件修改都会导致整个 bundle.js 文件重新构建的话,碰上大一点的项目,有几千个源文件要编译,编译速度降下来是必然的。webpack 有它的解决办法,具体参见。
在 html 文件中引用 bundle.js 文件后,我们有几个问题需要解决。
main.js 或它所引用的模块的变化如何通知 webpack,重新生成 bundle.js?
非常简单,在根目录下执行 webpack --watch 就可以监控目录下的文件变化并实时重新构建。
上面只是实时构建,我们该如何把结果通知给浏览器页面,让 HTML 页面上的 bundle.js 内容保持最新?
webpack 提供了
解决实时刷新页面的问题,同时解决实时构建的问题。
安装 webpack-dev-server
在全局环境中安装 webpack-dev-server:
npm install webpack-dev-server -g
在项目根目录下执行命令:
$ webpack-dev-server
这样,我们就可以在默认的 http://localhost:8080 网址上打开我们的 index.html。
此时,我们可能认为事情是按以下顺序发生的,
js 文件修改
webpack-dev-server 监控到变化
webpack 在内存中重新构建 bundle.js
webpack-dev-server 保证页面引用的 bundle.js 文件与内存中一致
但不幸的是,我们「自以为是」了。http://localhost:8080/index.html 对 js 文件的变化无动于衷。
webpack-dev-server 提供了用于自动刷新页面:
iframe 模式
我们不访问 http://localhost:8080,而是访问 http://localhost:8080/webpack-dev-server/index.html
inline 模式
在命令行中指定该模式,webpack-dev-server --inline。这样 http://localhost:8080/index.html 页面就会在 js 文件变化后自动刷新了。
以上说的两个页面自动刷新的模式都是指刷新整个页面,相当于点击了浏览器的刷新按钮。
webpack-dev-server 还提供了一种 ,属于较高阶的应用。
webpack 并不是包管理器,所以如果我们要使用第三方库,需要借助 npm。比如,在项目里安装 jQuery:
npm install jquery --save
这样我们在当前项目目录下安装了 jquery,并将它写入 package.json 里的依赖里。
模块化 JavaScript
如果我想用 ES6 的方式引入某个 es6 模块,比如:
import $ from 'whatever';
怎么办?浏览器目前还不提供原生支持,webpack 原生也仅支持 CommonJS 的那种写法,但借助
,我们可以加载 es6 模块:
安装 babel-loader
npm install babel-loader babel-core babel-preset-es2015 --save-dev
配置 webpack.config.js
在 module.exports 值中添加 module:
module.exports = {
app: ['./main.js']
filename: 'bundle.js'
loaders: [{
test: /\.js$/,
loaders: ['babel?presets[]=es;],
exclude: /node_modules/
这样我们就可以在我们的 js 文件中使用 ES6 语法,babel-loader 负责翻译。
上面的方法,是在 webpack.config.js 文件中给某一类型文件定义加载器,我们还可以在代码中直接指定:
import $ from 'babel!whatever'
当然,前一种方法会更优雅。
CSS 加载器
我们可以按传统方法使用 CSS,即在 HTML 文件中添加:
&link rel=&stylesheet& href=&style/app.css&&
但 webpack 里,CSS 同样可以模块化,使用 import 导入。
因此我们不再使用 link 标签来引用 CSS,而是通过 webpack 的
及 。前者将 css 文件以 &style&&/style& 标签插入 &head& 头部,后者负责解读、加载 CSS 文件。
安装 CSS 相关的加载器
npm install style-loader css-loader --save-dev
配置 webpack.config.js 文件
loaders: [
{ test: /\.css$/, loaders: ['style', 'css'] }
在 main.js 文件中引入 css
import'./style/app.css';
这样,在执行 webpack 后,我们的 CSS 文件就会被打包进 bundle.js 文件中,如果不想它们被打包进去,可以使用 。
模块化 CSS
上一步里,我们 import 到 JavaScript 文件中的 CSS 文件中的 CSS 在打包后是仍然是全局的,也就是说,我们只是换了种加载 CSS 的方式,在书写 CSS 的时候,还是需要注意使用,否则全局环境 CSS 类的冲突等问题不会消失。
这里,webpack 做了一个,真正意思上的「模块化」,即 CSS 类不会泄露到全局环境中,而只会定义在 UI 模块内 – 类似 react.js 这类模块,或者 。
autoprefixer
我们在写 CSS 时,按 CSS 规范写,构建时利用 autoprefixer 可以输出 -webkit、-moz 这样的浏览器前缀,webpack 同样是通过 。
安装 autoprefixer-loader
npm install autoprefixer-loader --save-dev
配置 webpack.config.js
loaders: [{
test: /\.css$/,
loader: 'style!css!autoprefixer?{browsers:[&last 2 version&, && 1%&]}',
重启 webpack-dev-server
假如我们在 CSS 中写了 body { display: } 规则,再查看 bundle.js 文件的话,我们能看到类似如下的代码:
body {\n\tdisplay: -webkit-\n\tdisplay: -webkit-\n\tdisplay: -ms-\n\tdisplay:\n}
图片同样可以是模块,但使用的是
或者 ,后者会根据定义的大小范围来判断是否使用 data url。
import loadingIMG from 'file!../img/loading.gif'
React.render(&img src={loadingIMG} /&, document.getElementById('app'));
打包、构建
项目结束后,代码要压缩、混淆、合并等,只需要在命令行执行:
即可,webpack 根据 webpack.config.js 文件中的配置路径、构建文件名生成相应的文件。通常,我们会额外定义一个专门用于生产环境的配置文件,比如 webpack.production.config.js,其中可以做许多代码优化。
相关热门文章autoprefixer
官方是这样说的:Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website,也就是说它是一个自动检测兼容性给各个浏览器加个内核前缀的插件。
举个栗子:最新的弹性盒模型flux实际代码:
:fullscreen
插件自动补充后
效果显而易见,我们可以更专注于css布局和美化,而不需要花过多的精力都写相同的外码而加上不同的前缀,也减少了冗余代码。
cnpm install --save-dev autoprefixer postcss-loader
var autoprefixer = require('autoprefixer');
module.exports={
html-webpack-plugin
cnpm install html-webpack-plugin --save-dev
作用:它会在dist目录下自动生成一个index.html
&!DOCTYPE html&
其他配置参数:
entry: 'index.js',
path: 'dist',
filename: 'bundle.js'
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
filename: 'admin.html',
template:'header.html',
inject: 'body',
favicon:'./images/favico.ico',
minify:true,
hash:true,
cache:false,
showErrors:false,
"chunks": {
"entry": "assets/head_bundle.js",
"css": [ "main.css" ]
xhtml:false
--- header.html ---
&!DOCTYPE html&
title: 设置title的名字
filename: 设置这个html的文件名
template:要使用的模块的路径
inject: 把模板注入到哪个标签后 'body',
favicon: 给html添加一个favicon
'./images/favico.ico',
minify:是否压缩
{...} | false (最新api变动,原来是ture|false 感谢@onmi指正)
hash:是否hash化 true false ,
cache:是否缓存,
showErrors:是否显示错误,
chunks:目前没太明白
xhtml:是否自动毕业标签 默认false
extract-text-webpack-plugin
官网是这么解释的Extract text from bundle into a file.,把额外的数据加到编译好的文件中
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
plugins: [
new HtmlWebpackPlugin({
template: './src/public/index.html',
inject: 'body'
new ExtractTextPlugin("[name].[hash].css")
说明:将css放到index.html的body上面
copy-webpack-plugin
官方这样解释&Copy files and directories in webpack,在webpack中拷贝文件和文件夹
cnpm install
作用:把public 里面的内容全部拷贝到编译目录
参数作用其他说明
定义要拷贝的源目录
from: __dirname + '/src/public'
定义要烤盘膛的目标目录
from: __dirname + '/dist'
file&或者&dir
可选,默认是文件
强制覆盖先前的插件
可选 默认false
不知道作用
可选 默认 base context 可用 specific context
只拷贝文件不管文件夹
默认是false
忽略拷贝指定的文件
可以用模糊匹配
webpack.ProvidePlugin [webpack内置插件 ]
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
new webpack.NoErrorsPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new monsChunkPlugin('common.js')
作用: 和上面5个一一对应
当模块使用这些变量的时候,wepback会自动加载。(区别于window挂载,感谢@lihuanghe121指正)
不显示错误插件
查找相等或近似的模块,避免在最终生成的文件中出现重复的模块
丑化js 混淆代码而用
提取公共代码的插件
'use strict';
if (isTest) {
config.devtool = 'inline-source-map';
作用: 使用source-map可以在debug的时候看到源代码,方便 查错
阅读(...) 评论()Webpack 性能优化 (一) - 推酷
Webpack 性能优化 (一)
Webpack 是 OneAPM 前端技术栈中很重要的一部分,它非常好用,如果你还不了解它,建议你阅读这篇
,在 OneAPM 我们用它完成静态资源打包,ES6 代码的转换 ,React 组件的组织等,在接下来的日子里,我们将通过一系列文章和业界分享我们在使用 Webpack 过程中关于性能方面的经验。
作为系列文章的第一篇,我们会重点介绍 Webpack 中的
resolve.alias
,也就是请求重定向。不过请注意 Webpack 里的请求是对模块的依赖,也就是一个
语句,而不是一个 HTTP 请求。
必要的准备
需要你有一定的 Node.js 基础
电脑上装有最新版的 Webpack (
npm install webpack -g
了解 Webpack 配置文件的格式
例子:本地时钟
要实现的功能很简单,就是在页面上用中文显示当前时间,需要用到
这个库,这个库封装了很多和日期相关的函数,而且自带了国际化的支持。
新建一个 Node.js 项目
初始化你的项目,然后通过
npm install moment -D
的开发者依赖。
作为入口文件,当然你也可以用
这样的名字,只是大部分的 Webpack 示例都是用的是
var moment = require('moment');
document.write(moment().locale('zh-cn').format('LLLL'));
新建一个页面
index.html
&h5&当前时间:&/h5&
&script src=&dist/bundle.js&&&/script&
此时的文件目录看起来是这样的:
index.html
package.json
node_modules/moment
到目前为止
这个文件还不存在,不过别着急,接下来的工作就交给 Webpack 来完成。
index.html
------------------------+
package.json
+--& &Clock App&
+--&bundle.js+--+
node_modules/moment-+
如图,Webpack 会把
模块一起打包成一个 bundle.js 文件,和
index.html
一起构成了我们的 Clock App。怎么样,是不是已经听到 Clock App 滴答作响了?
使用 webpack 打包代码
在命令行执行:
webpack --entry ./entry.js --output-path dist --output-file bundle.js
你会看到类似下面的输出结果:
Hash: bfcb30e3ef7
Version: webpack 1.10.0
Time: 650ms
Chunk Names
[0] ./entry.js 125 bytes {0} [built]
+ 86 hidden modules
可以看到,耗时 650ms,这么慢着实让人意外,一定要想办法提高“新一代神器”速度;另一方面,最后一行的
+ 86 hidden modules
非常让人怀疑:明明是一个简单的 Clock App,怎么会有这么多的依赖。
如何快速定位 Webpack 速度慢的原因
再一次,在命令行输入:
webpack --entry ./entry.js --output-path dist --output-file bundle.js \
--colors \
--profile \
--display-modules
不过这次新增加了三个参数,这三个参数的含义分别是:
输出结果带彩色,比如:会用红色显示耗时较长的步骤
输出性能数据,可以看到每一步的耗时
--display-modules
默认情况下
node_modules
下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
这次命令行的结果已经很有参考价值,可以帮助我们定位耗时比较长的步骤
Hash: bfcb30e3ef7
Version: webpack 1.10.0
Time: 650ms
Asset Size
Chunk Names
[0] ./entry.js 125 bytes {0} [built]
factory:11ms building:8ms = 19ms
[1] ../~/moment/moment.js 102 kB {0} [built]
[0] 19ms -& factory:7ms building:141ms = 167ms
[2] (webpack)/buildin/module.js 251 bytes {0} [built]
[0] 19ms -& [1] 148ms -& factory:132ms building:159ms = 458ms
[3] ../~/moment/locale ^\.\/.*$ 2.01 kB {0} [optional] [built]
[0] 19ms -& [1] 148ms -& factory:6ms building:10ms dependencies:113ms = 296ms
[4] ../~/moment/locale/af.js 2.57 kB {0} [optional] [built]
[0] 19ms -& [1] 148ms -& [3] 16ms -& factory:52ms building:65ms dependencies:138ms = 438ms
..... 广告分割线,Node.js 工程师简历请发
[85] ../~/moment/locale/zh-cn.js 4.31 kB {0} [optional] [built]
[0] 22ms -& [1] 162ms -& [3] 18ms -& factory:125ms building:145ms dependencies:22ms = 494ms
[86] ../~/moment/locale/zh-tw.js 3.07 kB {0} [optional] [built]
[0] 22ms -& [1] 162ms -& [3] 18ms -& factory:126ms building:146ms dependencies:21ms = 495ms
从命令行的结果里可以看到从 Request[4] 到 Request[86] 都是在解析
附带的大量本地化文件。所以我们遇到的速度慢的问题其实是由
如果你想知道为什么 Webpack 会加载这么多的模块,可以参考这篇文章
我们再来看看
代码的第一行,标准的
var moment = require('moment');
也就是说,请求的是
的源码。实际上,通过 NPM 安装
的时候会同时安装
的源码和压缩后的代码,试验证明下面这种写法也是可行的:
var moment = require('moment/min/moment-with-locales.min.js');
只不过这样改,可读性会有所下降,而且每一个用到
的地方都得这么写。另外,如果同样的问题出现在第三方模块中,修改别人代码就不那么方便了。下面来看看用 Webpack 怎么解决这个问题。
在 Webpack 中使用别名
resolve.alias
) 是 Webpack 的一个配置项,它的作用是把用户的一个请求重定向到另一个路径,例如通过修改
webpack.config.js
配置文件,加入:
resolve: {
moment: &moment/min/moment-with-locales.min.js&
这样待打包的脚本中的
require('moment');
其实就等价于
require('moment/min/moment-with-locales.min.js');
。通过别名的使用在本例中可以减少几乎一半的时间。
Hash: cdeaee0741a
Version: webpack 1.10.0
Time: 320ms
Asset Size
Chunk Names
[0] ./entry.js 125 bytes {0} [built]
factory:11ms building:9ms = 20ms
[1] ../~/moment/min/moment-with-locales.min.js 146 kB {0} [built] [1 warning]
[0] 20ms -& factory:8ms building:263ms = 291ms
[2] (webpack)/buildin/module.js 251 bytes {0} [built]
[0] 20ms -& [1] 271ms -& factory:3ms building:1ms = 295ms
WARNING in ../~/moment/min/moment-with-locales.min.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./locale in */webpack_performance/node_modules/moment/min
@ ../~/moment/min/moment-with-locales.min.js 1:
在 Webpack 中忽略对已知文件的解析
module.noParse
的另一个很有用的配置项,如果你
确定一个模块中没有其它新的依赖
就可以配置这项,
将不再扫描这个文件中的依赖。
noParse: [/moment-with-locales/]
这样修改,再结合前面重命名的例子,更新后的流程是:
重定向,转而请求
moment/min/moment-with-locales.min.js
/moment-with-locales/
一条生效,所以
就直接把依赖打包进了
Hash: 38b4ed70b9
Version: webpack 1.10.0
Time: 76ms
Chunk Names
[0] ./entry.js 125 bytes {0} [built]
factory:13ms building:13ms = 26ms
[1] ../~/moment/min/moment-with-locales.min.js 146 kB {0} [built]
[0] 26ms -& factory:13ms building:5ms = 44ms
时间进一步被压缩,只需要 76ms,比前一步还减少了 75%。
在 Webpack 中使用公用 CDN
Webpack 是如此的强大,用其打包的脚本可以运行在多种环境下,Web 环境只是其默认的一种,也是最常用的一种。考虑到 Web 上有很多的公用 CDN 服务,那么 怎么将 Webpack 和公用的 CDN 结合使用呢?方法是使用
声明一个外部依赖。
externals: {
moment: true
当然了 HTML 代码里需要加上一行
&script src=&///libs/moment/2.8.3/moment-with-locales.min.js&&&/script&
这次打包,结果只用了 49 ms,几乎达到了极限。
本文结合本地时钟的例子,展示了定位 Webpack 性能问题的步骤,以及所需要的两个参数 :
--display-modules
。然后,重点介绍了
resolve.alias
即利用别名做重定向的方法和场景,在此基础上,配合
module.noParse
忽略某些模块的解析可以进一步加快速度。最后介绍了用
定义外部依赖方法来使用公用 CDN。
本文相关的源码在:
本文由OneAPM工程师原创 ,想阅读更多技术文章,请访问OneAPM官方技术博客。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致webpack生成bundle.js文件为什么那么大,会影响加载速度吗_百度知道

我要回帖

更多关于 webpack 异步加载 的文章

 

随机推荐