webpack入门
webpack简述
按照webapck官网所说,webpack是一个模块打包工具(webpack is a module bundler)。它接收依赖的模块,将其转化为静态资源。
webpack与众不同的三大核心概念
-
Code Spliting
-
Loaders
-
Plugin System
配置(configuration)
CLI
如果使用CLI,webpack将会读取webpack.config.js文件(或者通过--config选项传递的文件),这个文件需要暴露这样的配置对象:
module.exports = {
// configuration
};
常见CLI option
1)开发环境简写 -d
等价于:--debug --devtool source-map --output-pathinfo
2)生产环境简写 -p
等价于:--optimize-minimize --optimize-occurrence-order
3)监视模式 --watch
4)配置文件 --config example.config.js
指定新的配置文件,而不是默认的webpack.config.js
5)常见的显示选项
- --progress
- --display-chunks
- --display-reasons
- --display-error-details
- --display-modules
- --display-exclude
可以通过script来定义脚本,然后npm run 命令名。
一个简单的配置对象,注意不是json,只是简单的object
{
context: __dirname + "/app",
entry: "./entry",
output: {
path: __dirname + "/dist",
filename: "bundle.js"
}
}
context
context:根目录(绝对路径!)。可以认为是文件查找的上下文。默认process.cwd()
entry
entry:包的入口点,有三种形式
-
一个string
-
一个由多个string构成的array
-
一个object(多页面场景下),key是chunk的name,value可以是string或者array
output
output.filename
不要在这里指定绝对路径
多入口情况下使用占位符
- [name] 模块名称
- [hash] 模块编译后的(整体)Hash值
- [chunkhash] 分片的Hash值,可以认为是文件的版本号,也可以认为是文件的MD5值,在静态资源的版本管理中非常有用
output.path
output.publicPath
指定 public URL地址,当我们要将output的文件放在不同的域名或者CDN上时十分有用
module
module.loaders 一个自动应用的loaders的数组,每项(item)可以有这些属性:
- test: A condition that must be met
- exclude: A condition that must not be met
- include: An array of paths or files where the imported files will be transformed by the loader
- loader: A string of “!” separated loaders
- loaders: An array of loaders as string
resolve
resolve.alias
模块别名定义,方便后续直接引用别名
resolve: {
alias: { AppStore : 'js/stores/AppStores.js',//之后直接 require('AppStore')
}
}
resolve.root
包含你模块的目录(绝对路径),也可以是一个目录数组,这个设置应该被用于添加个人目录到webpack查找路径里
必须是个绝对路径,不要这样写./app/modules
resolve.modulesDirectories
这是一个目录数组,用来解析到当前目录以及祖先目录和查找模块。这个函数的工作原理和node如何查找node_modules目录很像。比如如果值为["mydir"],webpack会查找“./mydir”, “../mydir”, “../../mydir”等等
默认: ["web_modules", "node_modules"]
resolve.extensions
一个用来解析模块的拓展名数组。比如,为了发现一个CoffeeScript文件,你的数组里应该包含字符串".coffee"
默认: ["", ".webpack.js", ".web.js", ".js"]
注意:设置这个选项将会重写默认值
externals
指定不该被webpack打包的模块,但是在打包后的包中仍然保留了请求。
我们可以通过它来暴露全局变量,而在需要的文件中直接require或import就可以了
externals: {
jquery: 'jQuery'
}
plugins
给编译器添加额外的插件
各种loaders
webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js 来很简单地编写自己的 loader。
loader的使用有三种方法,分别是:
- 在require中显式指定,即上面看到的用法
- 在配置项(webpack.config.js)中指定
- 在命令行中指定
转换ES6语法或React语法
通过presets选择ES6特性,也可以在package.json中指定
解决babel-loader处理React的preset问题:npm i --save-dev babel-preset-react
2)css相关
- style-loader 将模块的导出作为样式添加到DOM中
- css-loader 解析CSS文件后,使用import加载,并且返回CSS代码,可以在loader后面?modules以支持CSS Module
- less-loader 加载和转译LESS文件
- sass-loader 加载和转译SASS/SCSS文件,须先安装node-sass,windows可能安装出错,使用cnpm i node-sass --save-dev或者如下:
npm install --save-dev node-sass --registry=https://registry.npm.taobao.org --disturl=https://npm.taobao.org/dist --sass-binary-site=http://npm.taobao.org/mirrors/node-sass
- postcss-loader 使用PostCSS加载和转译CSS/SSS文件,可以进行autoprefixer
CSS中@import另一个CSS怎么处理?(非SASS、LESS)
给css-loader添加参数
loader: 'style-loader!css-loader?importLoaders=1!postcss-loader'
3)模板相关
- html-loader 导出HTML为字符串,需要引用静态资源
- jade-loader 加载Jade模板并返回一个函数
- markdown-loader 将Markdown转译为HTML
- handlebars-loader 将Handlebars转换为HTML
- ejs-loader 将underscore模板转换为HTML
4)图片相关
- file-loader
- url-loader 与file-loader,但如果文件小于限制,可以返回 data URL
- image-loader 压缩图片
components模板引用相对路径图片不会替换?
可以使用绝对路径或者这样写src="${require('../../assets/bg.png')}"
5)bundle-loader
bundle-loader是一个用来在运行时异步加载模块的loader。可以用来做代码分割
6)exports-loader
可以从模块中导出变量。
在实际使用中,用exports-loader最多的场景是将某些不支持模块化规范的模块所声明的全局变量作为模块内容导出。
如下可以导出全局变量Hello,exports-loader还可以支持同时导出多个变量,例如exports?HELLO,WORLD
module.exports = {
module:{
loaders:[
{ test: require.resolve('./hello'), loader: "exports?Hello" }
]
}
};
7)imports-loaders
用于向一个模块的作用域内注入变量(Can be used to inject variables into the scope of a module)
8)expose-loader
把一个模块导出并付给一个全局变量
require("expose?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.
各种plugins
参数:
- template html模板地址,默认为webpack.config.js所在的目录
- inject 插入位置
- title
- date等
2)CommonsChunkPlugin
将多个入口起点之间共享的公共模块,生成为一些 chunk,并且分离到单独的 bundle 中,例如,1vendor.bundle.js 和 app.bundle.js
3)ExtractTextWebpackPlugin
从 bundle 中提取文本(CSS)到分离的文件(app.bundle.css)
4)ProvidePlugin
ProvidePlugin可以将模块作为一个变量,被webpack在其他每个模块中引用。只有你需要使用此变量的时候,这个模块才会被 require进来。多数之前遗留的模块,会依赖于已存在的某些特定全局变量,比如jQuery插件中的$或者jQuery。在这种场景,你可以在每次遇到全局标识符$的时候,在webpack中预先设置var $ = require(“jquery”)。
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
Environment flags
windows下使用cross-env的npm包兼容处理,可以在package.json设置如下:
"scripts": {
"clear": "rm -rf build&& mkdir build",
"start": "npm run clear&& cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --devtool eval --progress --color --profile",
"deploy": "npm run clear&& cross-env NODE_ENV=production webpack -p --progress"
}
webpack.config.js
var isProduction = process.env.NODE_ENV === 'production';
plugins: [new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}
})]
Code splitting(代码分割)
使用require.ensure
// main.js
require.ensure(['./a'], function(require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
// a.js
module.exports = 'Hello World';
require.ensure告诉Webpack,./a.js应该从bundle.js分离并且打包成一个单独的文件
注意require.ensure只会加载模块而不会去解析
也可以用bundle-loader进行代码分割
// main.js
// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');
// To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
vendor chunk
可以用CommonsChunkPlugin插件将公共库(vendor)打包成一个单独的文件
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.js')
]
};
模块热替换(Hot Module Replacement)
npm i webpack-dev-server --save-dev