webpack 总结 - archering/basic GitHub Wiki

webpack核心功能:

  1. 模块划分
  2. 按照模块的依赖顺序将多个module合并成一个bundle文件,在浏览器上运行。

webpack支持目前已知的三种主要module系统

  1. commonJS
  2. AMD
  3. ES6(ES2015,import,export)

要使用webpack 必须先安装webpack

 npm install webpack@2.* --save-dev

webpack的运行依赖一个webpack.config.js的配置文件。

这个配置文件基本结构和关键点是:

var config = {

entry:"./src/index.js",//入口文件地址 (相对路径,相对webpack.config.js)

output:{
    path:path.resolve(__dirname,"dist"), //(绝对路径) 合并文件bundle.js 地址
    filename:"bundle.js"//合并输出文件的名字
}

}

运行webpck 有两种方式

(1)如果你是全局安装的 webpack
npm install -g webpack 那么你可以直接在命令行输入 webpack 来运行程序

(2)如果你是本地安装的webpack 需要在package.json 里面配置

scripts:{
    "build":"webpack"
}
//然后在命令行输入
npm run build  //来运行webpack程序

babel 是一个node编译库(Babel is a JavaScript compiler),用来将ES6,ES7 转成目前浏览器支持的ES5
webpack 是一个node程序 用js写成,作用是将多个划分好的模块(js文件)合并成一个bundle

先解释下webpack是啥

webpack仅仅能明白和理解纯javascript,要想使webpack能处理其他语言或者不同版本的语言,比如css(css-loader),typscript(ts-loader),ES2016 ... 就需要一个预处理程序读取这些文件并将它们转成webpack能理解的东西。 webpack在它的配置文件中添加了一个module 属性,用于支持这种特性,当然可以支持多个。webpack文档专门有一节说明这个和用法。

module.rules allows you to specify several loaders within your webpack configuration

module 是webpack生成bundle之前预处理源程序的地方

例如下面webpack为了能够处理ES6的东西,就需要借助babel

如何使用babel,先要知道三个物件

babel-loader : Teach babel how to work with webpack

babel-core : Knows how to take in code,parse it, and generate some output code (输入输出机制)

babel-preset-env: 根据具体的语法规则将ES6/7/8转成 ES5, (BABEL的本职工作)

webpack 可以同时支持在一个项目里面使用多个module system


webpack module(loader)

	module:{
		rules:[
			{
				use:"babel-loader",
				test:/\.js$/
			},
			{
				use:["style-loader","css-loader"], //从右往左执行,先依赖css-loader处理,再依赖style-loader处理
				test:/\.css$/
			}
		]
	}

ES6 中import 有两种: 一种是引入并引用,需要module 显示的export default divi

import divi from "./divide"

另一种是引入并执行,不引用这里面的对象

import "./image_viewer";//引入并执行相关代码

plugins

webpack 提供的这个功能,Plugins range from bundle optimization and minification all the way to defining environment-like variables. (webpack的基本功能是将多个文件按照依赖加载顺序合并,plugins则提供了额外的功能,比如文件压缩,代码优化,分离文件,注释删除,变量替换等....)

对应的在webpack.config.js 提供了相应的plugins选项, (1)首先你需要npm install 安装这个插件,(2)然后在webpack.config.js 引入require这个插件,最后在plugins选项中列出这个插件的实例。

  const webpack = require('webpack'); //to access built-in plugins

  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]

按需加载相应的js文件

首先说明一个属性publicPath

var config = {

    entry:"./src/index.js",//入口文件地址 (相对路径,相对webpack.config.js)

    output:{
        path:path.resolve(__dirname,"dist"), //(绝对路径) 合并文件bundle.js 地址
        filename:"bundle.js",//合并输出文件的名字
        publicPath:"./dist/"  // 这个变量对于打包合并后的文件分开存放,split 文件很有用,知道去哪里放这些文件
    }

}

story: (1)首先页面一加载,显示在页面上的是一个按钮(此时页面上只加载了一个bundle.js)。 (2)用户点击按钮后加载另一个文件(0.bundle.js),并在页面上渲染一副图片。

image_viewer_split.js

let button = document.createElement("button");
button.innerHTML = "click me to show image";
button.onclick = () => { //点击之后加载一个新的js 
//System.import 回去服务端请求新的资源,返回一个promise, 这个方法类似fetch
	System.import("./image_viewer_itself").then((module) =>{ 
		module.default();
	});
}

document.body.appendChild(button);

image_viewer_itself.js

import "./css/image_viewer.css";// 1非js文件的import 都要加扩展名。 2 如果只是引入并执行文件,而不需要引用文件内容,可以只写引入地址 
//programmatic API   如果想基于某些条件或等某个事件发生后再加载需要的模块
//System.import方法  

export default () => {
	var img = document.createElement("img");
	img.src = "http://lorempixel.com/200/200/";// 这是一个线上服务,可以获得随机的照片

	document.body.appendChild(img);
}

这种情况下打包,就会在dist 下面出现两个包,一个是bundle.js 一个是 0.bundle.js 如果你在开发中有多个分段加载的js 则会生成0.bundle.js 1.bundle.js ....

story: 随着项目越写越大,引入的第三方框架约来越多, 利用webpack 打包输出一个bundle坑定不行。 我们最基本的需求,比如把自己写的js文件打包成一个bundle,第三方库合并成一个bundle 已经是最近本的需求了。 这个就需要改变两个东西,(1)修改webpack.config.js (2) 引入插件,分割bundle。

改变的第一个地方

var config = {
	entry:{
		bundle:"./src/js/index.js",
		vendor:['react','faker','redux'] //这里面是package.json 里面的所有dependencies 里面module
	},
	output:{
		path:path.resolve(__dirname,"dist"),
		filename:"[name].js"  //这里面变量[name] 就会从 entry 里面去取 key (bundle, vendor)生成相应的bundle.js vendor.js文件
	}

上面这种写法的结果会出现,打了两个bundle, bundle.js 和 vendor.js 但是bundle.js 里面还是包含了vendor.js 类似这个:

bundle.js  3.37 MB       0  [emitted]  [big]  bundle
vendor.js  3.14 MB       1  [emitted]  [big]  vendor

我们期望的是 把bundle.js里面包含的verdor部分删除,这就需要借助一个插件

	plugins:[
		new webpack.optimize.CommonsChunkPlugin({ //这个不需要require webpack自带的
			name:'vendor'  //要剔除的部分  和 entry 里面对应的key
		})
	]

结果如下,bundle.js变小了

bundle.js   228 kB       0  [emitted]         bundle
vendor.js  3.14 MB       1  [emitted]  [big]  vendor