说明
1.webpack工作内容
Webpack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
2.webpack工作方式
把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders,plugins处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
使用
1.如果在nodejs中全局安装了webpack和webpack-dev-server,可以在git bash直接使用’webpack’命令进行打包,使用’webpack-dev-server’命令启动打包后生成的项目
2.在打包之前,要先配置webpack.config.js文件,’webpack’命令会根据webpack.config.js文件的配置项去打包文件
3.如果想使用不同的配置文件去打包项目,可以使用’webpack –config 文件名’命令去打包
4.如果不想带文件名去打包,可以在package.json的scripts对象中配置命令‘xxx’,然后在git bash中使用命令‘npm run xxx’进行打包1
2
3
4
5"scripts": {
"start": "webpack-dev-server",
"build": "webpack --config webpack.config.build.js",
"dev":"webpack --config webpack.config.dev.js"
}
执行 npm run build 则按照webpack.config.build.js文件配置的内容去打包
同样,执行 npm run dev 则按照webpack.config.dev.js文件配置的内容去打包
但要注意,使用配置命令’start’时,直接执行’npm start’,就可以执行其对于的命令,中间不需要加run
webpack.config.js 配置
module.exports = {}
1.配置根路径
配置入口文件前,可以用context配置根路径,这样在配置时,就不用将文件路径写进去,直接将文件配置进去就可以了
可以借助path模块拼接路径字符串1
2
3
4
5
6
7
8const path = require('path')
module.exports = {
/**
* The base directory
*/
context: path.join(__dirname, './src'),//这样入口文件就是指src文件夹下面的那些文件
}
2.入口文件
入口文件是指打包后项目生成的可以访问的文件1
2
3
4
5
6
7
8
9//单入口:
entry: './index.js',/*打包单个文件*/
entry: ['./index1.js','./index2.js'],/*打包多个文件*/
//多入口:
entry: {
home: './home',
user: ['./user', './account']
},
多入口文件数组的KEY值可用于命名输出文件名,其对应的值即是要打包的源文件
3.输出文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15output: {
/* filename方式一:直接指定文件名*/
filename: 'bundle.js',
/* filename方式二:映射变量[name]和[hash],[name]即定义入口文件的key值,[hash]是webpack在打包的时候按照一定规则生成的值,是MD5加密的值,如果文件没有发生变化,hash值不会变,可用于版本控制
(CDN一般缓存时间比较长,文件发生变化,hash值就会变,文件名就会变,CDN就能及时更新文件)
* 还可以加[chunkhash],这里是作为版本号使用,方便上线时静态资源的版本管理
* 单入口[name]被映射成‘main’
*/
filename: '[name].bundle.[hash].js',
path: '/home/proj/public/assets',/*指定输入文件存放路径*/
libraryTarget:
}
4.配置加载器loader
loader 是对应用程序中资源文件进行转换。它们是(运行在 Node.js 中的)函数,可以将资源文件作为参数的来源,然后返回新的资源文件。
官方可用loader
Loaders的配置包括以下几方面:
test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
loader:loader的名称(必须)
include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
query:为loaders提供额外的设置选项(可选)
loader被配置在rules数组中,数组每一个对象可配置一个或多个loader
例:1
2
3
4
5
6
7
8
9module: {
rules: [
{
test: /\.js$/,
include: path.join(__dirname, './src'),
use: 'babel-loader'
}
]
},
常用loader:
babel-loader:编译js,考虑到babel具有非常多的配置选项,一般把babel的配置选项放在一个单独的名为 “.babelrc” 的配置文件中
css-loader:使你能够使用类似@import 和 url(…)的方法实现 require()的功能,获取css文件里面的样式
style-loader:将css样式插件js文件,与css-loader一起使用能够把样式表嵌入webpack打包后的JS文件中
autoprefixer-loader:自动添加前缀,使css文件更有兼容性
postcss-loader:css会自动根据Can i use里的数据添加不同前缀,可与autoprefixer-loader结合使用
ExtractTextPlugin.extract:将css单独打包成一个.css文件,使用这个插件,需要require 插件extract-text-webpack-plugin1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49//配置代码:
1.
module: {
rules: [
{
test: /\.css$/,
include: [
path.join(__dirname, './src')
],
use: ['style-loader', 'css-loader']
//链式调用loader的时候,会以数组逆序的顺序执行,
//先执行css-loder,再执行style-loader
}
]
},
2.
module: {
rules: [{
test: /\.css$/,
include: [
path.join(__dirname, './src'),
],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}]
},
plugins: [
new ExtractTextPlugin('[name].css')
]
3.
module: {
rules: [{
test: /\.css$/,
include: [
path.join(__dirname, './src')
],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'autoprefixer-loader']
})
}]
},
plugins: [
new ExtractTextPlugin('[name].css')
]
5.配置插件plugin
插件目的在于解决 loader 无法实现的其他事,配置插件都在plugin数组中,数组每一项就是new一个plugin,插件的配置也在new时以参数形式传递进去
例:1
2
3
4
5
6
7
8
9//打包公共文件方式一:
plugins: [
new CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js'
}),
new ExtractTextPlugin('[name].css')
]
常用插件:
CommonsChunkPlugin:将多个文件通用的东西打包成一个文件
webpack.optimize.CommonsChunkPlugin:require(‘webpack’),使用webpack的optimize.CommonsChunkPlugin将打包的文件转化为公共文件
HtmlWebpackPlugin:是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//打包公共文件方式二:
var path = require('path')
var webpack = require('webpack')
module.exports = {
context: path.join(__dirname, './src'),
entry: {
app: './',
vendor: ['jquery', 'underscore'],//将文件中require的'jquery', 'underscore'打包成公共文件vendor.bundle.js
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js'
})
]
}
写一个webpack 的loader
1.相当于写一个普通的模块1
2
3
4
5module.exports = function (source){
.....
...
return xxx
}
2.获取配置参数
方式一
直接使用API:this.query
方式二
使用loader-utils库1
2const loaderutils = require('loader-utils')
const options = loaderutils.getOptions(this);
3.处理模块依赖
方式一:转化成require语句
例如,css-loader将@import和url(…)替换会require(…)
方式二:使用this.resolve函数解析路径
例如,less-loader将less编译器进行扩展自定义路径解析逻辑然后利用this.resolve解析依赖
4.不要使用绝对路径
5.如果要包裹另外一个包将这个包作为peerDependency在package.json中引入
6.返回值
如果只是返回一个值可以用return
如果返回多个值需要调用API:this.callback(),但依然要在最后return一个undefined
7.本地配置使用
单个:path.resolve(‘../../loader.js’)1
2
3
4
5
6
7
8
9{
test: /\.js$/
use: [
{
loader: path.resolve('path/to/loader.js'),
options: {/* ... */}
}
]
}
多个或一个1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18module: {
rules: [
{
test: /\.js/,
use: [{
loader:'define-loader',
options:{name:'alice'}
}
],
}
]
},
resolveLoader: {
modules: [
'node_modules',
path.resolve(__dirname, 'loaders')
]
}
中文
How to write a loader
loader API
写一个webpack 的plugin
按照格式,根据compiler 和 compilation 对象处理流程上的钩子函数,
在不同阶段插入我们要做的事情
1.格式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class DefPlugin {
constructor(name) {
}
apply(compiler) {
// 指定挂载的webpack事件钩子。
compiler.plugin("compile", function(params) {
console.log("The compiler is starting to compile...");
});
// 指定挂载的webpack事件钩子。
compiler.plugin('emit', function(compilation, callback) {
// 现在设置回调来访问编译中的步骤:
compilation.plugin("optimize", function() {
console.log("Assets are being optimized.");
});
//功能完成后调用webpack提供的回调。
callback();
})
}
}
module.exports = DefPlugin
2.使用
直接在webpack.config.js文件中require一下就好1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Plugin = require('./myplugin')
module.exports = {
context: path.join(__dirname, 'src'),
entry: './index.js',
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, 'dist'),
filename: './bundle.js'
},
plugins: [
new Plugin
]
}
3.compiler
compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并在所有可操作的设置中被配置,包括原始配置,loader 和插件。当在 webpack 环境中应用一个插件时,插件将收到一个编译器对象的引用。可以使用它来访问 webpack 的主环境。
源码
4.compilation
compilation 对象代表了一次单一的版本构建和生成资源。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,一次新的编译将被创建,从而生成一组新的编译资源。一个编译对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。编译对象也提供了很多关键点回调供插件做自定义处理时选择使用
源码
5.tabable
webpack性能优化
1.将不再使用的依赖及时删除
2.不要为了实现小功能引入大型lib
3.合理配置babel
4.根据使用场景合理使用优化插件
例如使用happypack,webpack-uglify-parallel 在开发阶段进行多核并行压缩
相关链接
学习链接
gulp
api:
task:
src:
watch:用来监视文件的变化;
jshint:js 代码检查
uglify:压缩js
minify-css:压缩css
minfy-html:压缩html
concat:合并文件
babel
babel是一个js转换器
可以将es6,es7,react/jsx的语法通过他的插件转编译成es5的或者说支持在现有环境运行的语法
使用babel,除了可以使用package.json进行配置,一般会为它建立专门的.babelrc文件进行配置1
2
3
4{
"presets": [],
"plugins": []
}
使用babel-preset-env转换es5,就将‘env’添加到.babelrc的presents数组中
使用babel-preset-react转换jsx,就将‘react’添加到.babelrc的presents数组中
使用babel-preset-stage-x转换es7不同阶段语法,就将‘stage-x’添加到.babelrc的presents数组中,x目前可以为0,1,2,3
使用babel-core模块,可以在代码中手动调用babelAPI进行转码
使用babel-polyfill模块,可以转换新版es6/es7里面的API,如generator,Symbol,Promise等
安装babel-cli实现命令行进行转码
另外babel经常用于前置转码,比如与eslint结合进行代码检查,与mocha进行脚本测试