webpack2

使用webpack构建项目

webpack核心概念

webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成少量的 bundle - 通常只有一个,由浏览器加载。

webpack

环境依赖

  • node

项目初始化

创建项目

创建一个webpack-demo项目并生成package.json文件。之后所有操作的根目录均为webpack-demo/

mkdir webpack-demo
cd webpack-doemo
npm init -f

引入webpack

npm install --save-dev webpack

项目初始结构分析

通常项目会分成三个运行环境:开发人员在本地跑的开发环境(dev)、测试人员用来做黑盒测试的测试环境(test)和线上运行的生产环境(production)
简单起见,本文只考虑开发环境(dev)和生产环境(prod),测试环境可以自行类比。


起步

webpack.config.js

//引入Node.js Path模块
const path = require('path);

module.exports = {
    entry:'./src/index.js',// string | object | array
    // 这里应用程序开始执行
    // webpack 开始打包
    output:{
        filename:'bundle.js',// string
    // 「入口分块(entry chunk)」的文件名模板(出口分块)
        path:path.resolve(__dirname,'dist') // string
    // 所有输出文件的目标路径
    // 必须是绝对路径(使用 Node.js 的 path 模块)
    }
}

path

  • 直接编译
        $ webpack
    
  • 基于NPM 脚本(NPM Scripts)
       $ npm run build
    
    • package.json

          {
          ...
          "scripts": {
              "build": "webpack"
          },
          ...
          }
      

管理资源

加载CSS

安装style-loadercss-loader

$ npm install --save-dev style-loader css-loader

src/index.js

+ impost './style.css';

webpack.config.js

const path = require('path');

module.exports = {
  entry:'./src/index.js',
  output:{
    filename:'bundle.js',
    path:path.resolve(__dirname,'dist')
  },
  module:{
    rules:[
      {
        test:/\.css$/,
        use:[
          'style-loader',
          'css-loader'
        ]
      }
    ]
  }
};

webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader。在这种情况下,以 .css 结尾的全部文件,都将被提供给 style-loader 和 css-loader。

加载图片

安装file-loader

$ npm install --seve-dev file-loader    

index.js

+ impost Icon from './icon.png';

webpack.config.js

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

加载字体,加载数据

管理输出

设定 HtmlWebpackPlugin

这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。

$ npm install --save-dev html-webpack-plugin

webpack.config.js

...
plugins:[
    new HtmlWebpackPlugin({
      title: 'Output Management'
    })
  ],
...

清理 /dist 文件夹

一个webpack插件在构建之前删除/清理你的构建文件夹

$ npm install clean-webpack-plugin --save-dev

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
  entry: { 
    app: './src/index.js',
    print: './src/print.js'
  },
  plugins:[
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Output Management'
    })
  ],
  output: {
    filename:'[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
};

开发

使用source map

对错误可追踪到源文件
webpack.config.js

module.exports = {
  ...
  devtoll:'inline-source-map'
  ...
}

现在在浏览器打开最终生成的 index.html 文件,点击按钮,并且在控制台查看显示的错误。错误应该如下:

 Uncaught ReferenceError: cosnole is not defined
    at HTMLButtonElement.printMe (print.js:2)

选择一个开发者

webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:

  1. webpack's Watch Mode
  2. webpack-dev-server
  3. webpack-dev-middleware

多数情况使用webpack-dev-server

使用观察者模式

package.json

...
"scripts":{
  "watch":"webpack --watch",
  "build":"webpack"
}
...

使用wepack-dev-server

webpack-dev-server提供一个简单的web服务器,并且能实时重新加载(live reloading)。

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

webpack.config.js

module.exports = {
  ...
  devServer:{
    contentBase:'./dist'
  }
  ...
}

以上配置告知 webpack-dev-server,在 localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。
package

...
"scripts":{
  "start":"webpack-dev-server --open"
}
...

使用webpack-dev-middleware

webpack-dev-middleware

模块热替换

允许在运行时更新各种模块,而无需进行完全刷新。

概念

启用HMR

webpack.config.js

const webpack = requier('webpack');
module.exports = {
  entry:{
    app:'./src/index.js'
  },
  devServer:{
    contentBase:'./dist',
    hot:true
  }
  ...
    plugins:[
      new webpack.NamedChunksPlugin(),
      new webpack.HotModuleReplacementPlugin()
      //热加载插件
    ]
  ...
}

index.js

...
+ if (module.hot) {
+   module.hot.accept('./print.js', function() {
+     console.log('Accepting the updated printMe module!');
+     printMe();
+   })
+ }

HMR 修改样式表

webpack.config.js

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

index.js

+ import './styles.css';

Tree Shaking

用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 importexport

./src/mach.js

export function square(x){
  return x * x;
}
export function cube(x){
  return x * x * x;
}

index.js

import { cube } from "./math.js"

没有导出square,但是它仍被包含在编译后的文件中。

精简输出

$ npm install --save-dev uglifyjs-webpack-plugin

webpack.config.js

const UglifyjsPlugin = require('uglifyjs-webpack-plugin')

...
plugins:[
  new UglifyjsPlugin()
]
...

有复杂的依赖树的大型应用程序上运行时,tree shaking 或许会对 bundle 产生显著的体积优化。

生产环境构建

配置

开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source maplocalhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的webpack配置。

安装

webpack-merge是专门用来处理webpack.config.js的配置文件分离的。它主要提供一个merge方法,来将各个分开的配置项给合并在一起

$ npm install --save-dev webpack-merge

project

  webpack-demo
  |- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
  |- /dist
  |- /src
    |- index.js
    |- math.js
  |- /node_modules

webpack.common.js

+ const path = require('path');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+ module.exports = {
+   entry: {
+     app: './src/index.js'
+   },
+   plugins: [
+     new CleanWebpackPlugin(['dist']),
+     new HtmlWebpackPlugin({
+       title: 'Production'
+     })
+   ],
+   output: {
+     filename: '[name].bundle.js',
+     path: path.resolve(__dirname, 'dist')
+   }
+ };

webpack.dev.js

+ const merge = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+   devtool: 'inline-source-map',
+   devServer: {
+     contentBase: './dist'
+   }
+ });

webpack.prod.js

+ const merge = require('webpack-merge');
+ const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+   plugins: [
+     new UglifyJSPlugin()
+   ]
+ });

Minification

注意,虽然 UglifyJSPlugin 是代码压缩方面比较好的选择,但是还有一些其他可选择项。以下有几个同样很受欢迎的插件:

  • BabelMinifyWebpackPlugin
  • ClosureCompilerPlugin

source map

webpack.prod.js

  module.exports = merge(common, {
+   devtool: 'source-map',
    plugins: [
-     new UglifyJSPlugin()
+     new UglifyJSPlugin({
+       sourceMap: true
+     })
    ]
  })

避免在生产中使用 inline-***eval-***,因为它们可以增加 bundle 大小,并降低整体性能。

指定环境

CLI 替代选项

详情

代码分离

代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。

有三种常用的代码分离方法:

  • 入口起点:使用 entry 配置手动地分离代码。
  • 防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
  • 动态导入:通过模块的内联函数调用来分离代码。

入口起点(entry points)

简单,直观。手动配置较多,并有些陷阱。

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

推荐阅读更多精彩内容

  • 1. 新建一个文件夹,命名为 webpack-cli , webpack-cli 就是你的项目名,项目名建议使用小...
    鲁大师666阅读 1,459评论 1 3
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,134评论 7 35
  • webpack 介绍 webpack 是什么 为什么引入新的打包工具 webpack 核心思想 webpack 安...
    yxsGert阅读 6,440评论 2 71
  • 背景 一直对webpack的打包流程很感兴趣,但是无奈官网文档实在太多,搜出来的大部分文章要么偏理论要么纯粹讲过程...
    AllenGKC阅读 610评论 0 0
  • php artisan make:migration creat_students_table --create=...
    孟维学阅读 157评论 0 0