entry
)、输出(output
)、loader
、插件(plugins
)1、在项目中安装webpack:在根目录下打开命令窗口,输入 npm install webpack --save-dev
安装webpack。
2、在js文件中引入另外一个js文件,如:在根目录下的 hello.js 中引入根目录下的 world.js
require('./world.js');
3、webpack 打包文件命令:webpack 要打包的文件 打包后的文件
如:webpack hello.js hello.bundle.js
4、在js中引入css文件:
webpack本身是不支持 .css 格式的,需要使用loader插件
(npm install css-loader style-loader --save-dev
)
css-loader
:使webpack能处理 .css 文件
style-loader
:将css-loader处理过的css用style标签包裹起来插入到HTML里面
有以下两种方式:
(1)require(‘style-loader!css-loader!./style.css’) // 插件通过 ! 连接
(2)require(’./style.css’)
打包命令为:webpack hello.js hello.bundle.js --module-bind 'css=style-loader!css-loader'
如果要实现内容改变自动打包则:webpack hello.js hello.bundle.js --module-bind 'css=style-loader!css-loader' --watch
5、通过命令创建文件夹:mkdir 文件夹名称
6、使用webpack命令的话,webpack会默认使用根目录下的webpack.config.js
,将其作为默认的配置。
也可通过 --config
来使用其他配置文件,例如:webpack --config webpack.dev.config.js
7、commenJS的模块化输出:module.exports = {}
8、wenpack.config.js配置文件
entry
:打包入口从哪个文件开始
output
:打包以后的文件放在哪,并且定义打包以后的文件名
最基本的配置:
module.exports = {
entry: './src/script/main.js',
output: {
path: './dist/js',
filename: 'bundle.js',
},
}
9、在 package.json 中配置 webpack 命令
在 "scripts": {...}
, 中添加如下:
"webpack": "webpack --config webpack.config.js --progress --display-module --colors --display-reason",
然后在命令窗口输入:npm run webpack
--progress
:看到打包的过程
--display-module
:查看打包的模块
--colors
:打包时出来的字是彩色的
--display-reason
:查看打包的原因
10、entry
:有三种输入方式
(1)entry: './src/script/main.js',
(2)entry: ['./entry1', './entry2'] // 两个平行的不相依赖的文件打包到一起
(3)用于多页面应用
{
entry: {
page1: './page1',
page2: ['./entry1', './entry2']
},
output: {
fillname: '[name].bundle.js', // [name]-[hash].js [name]-[chunkhash].js
chunkFilename: '[id].bundle.js'
}
}
11、webpack插件:html-webpack-plugin
安装命令:npm install html-webpack-plugin --save-dev
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins:[
new htmlWebpackPlugin({
template: 'index.html'
})
]
}
filename: 'index-[hash].html', // 指定生成的文件名称,一般直接使用 index.html
template: 'index.html', // 模板
inject: 'head', // 指定生成的脚本放在的位置,放在head标签中还是会放在body标签中
minify:{ // 压缩html文件
removeComments: true, // 删除注释
collapseWhitespace: true, // 删除空格
}
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins:[
new htmlWebpackPlugin({
filename: 'index-[hash].html',
template: 'index.html',
inject: 'head',
title: 'webpack is good',
date: new Date()
})
]
}
在index.html中引用(类似模板引擎):
<title><%= htmlWebpackPlugin.options.title %>title>
<div> <%= htmlWebpackPlugin.options.date %> div>
<div>
<% for(var key in htmlWebpackPlugin){ %>
<%= key %>
<% } %>
div>
<div>
<% for(var key in htmlWebpackPlugin.file){ %>
<%= key %>:<%= JSON.stringify(htmlWebpackPlugin.file[key]) %>
<% } %>
<% for(var key in htmlWebpackPlugin.options){ %>
<%= key %>:<%= JSON.stringify(htmlWebpackPlugin.options[key]) %>
<% } %>
div>
12、设置打包上线后的地址,设置 output 的 publicPath
属性
module.exports = {
...
output: {
path: './dist',
filename: 'js/[name]-[chunkhash].js',
publicPath: '', // 如设为:http://cdn.com/
},
...
}
publicPath
:在 html 中引用的 js 的路径会替换为绝对地址以 publicPath 设置的值开头的路径。
13、使用 html-webpack-plugin 生成多页面html
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/script/main.js',
a: './src/script/a.js',
b: './src/script/b.js',
c: './src/script/c.js',
},
output: {
path: './dist',
filename: 'js/[name]-[chunkhash].js',
publicPath: '', // 如设为:http://cdn.com/
},
plugins:[
new htmlWebpackPlugin({
filename: 'a.html',
template: 'index.html',
inject: 'body',
title: 'this is a',
chunks: ['main', 'a'], // 指向entry中的key,表示引用main.js和a.js
excludeChunks: ['b','c'] // 表示引用除了b.js和c.js之外的js
}),
new htmlWebpackPlugin({
filename: 'b.html',
template: 'index.html',
inject: 'body',
title: 'this is b',
chunks: ['b']
}),
new htmlWebpackPlugin({
filename: 'c.html',
template: 'index.html',
inject: 'body',
title: 'this is c',
chunks: ['main', 'c']
})
]
}
14、优化:将 js 直接插入到 html 页面,而不是引用 js 文件,这样可以减少 http 请求
<script type="text/javascript">
<% compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
</script>
<% for(var k in htmlWebpackPlugin.files.chunks){ %>
<% if(k !== 'main'){ %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks[k].entry %>"></script>
<% } %>
<% } %>
15、loader
var htmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path'); // nodejs中的path
module.exports = {
entry: ...',
output: {...},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel', // npm 安装:npm install --save-dev babel-loader babel-core
exclude: './node_modules/',
include: './src/',
query: {
presets: ['latest'] // 安装:npm install --save-dev babel-preset-latest
// 也可以在 package.json 进行配置,即与script并列的添加属性:"babel":{"presets":["latest"]}
}
},{
test: /\.js$/,
loader: 'babel', // npm 安装:npm install --save-dev babel-loader babel-core
// exclude: './node_modules/',
exclude: path.resolve(__dirname, 'node_modules'),
// include: './src/',
include: path.resolve(__dirname, 'src'),
query: {
presets: ['latest'] // 安装:npm install --save-dev babel-preset-latest
// 也可以在 package.json 进行配置,即与script并列的添加属性:"babel":{"presets":["latest"]}
}
},{
test: /\.html$/,
loader: 'html-loader',
},{
test: /\.ejs$/, // 也可将文件后缀改为tpl
loader: 'ejs-loader',
},{
test: /\.css$/,
loader: 'style-loader!css-loader?importLoaders=1!postcss-loader',
},{
test: /\.less$/,
loader: 'style!css!postcss!less',
},{
test: /\.scss$/,
loader: 'style!css!postcss!sass',
},{
test: /\.(png|jpg|gif|svg))$/i,
// loader: 'file-loader',
loader: 'url-loader?limit=1000&name=assets/[name-[hash:5].[ext]',
/* query: { // 指定图片打包路径
name: 'assets/[name]-[hashs].[ext]'
} */
}],
},
postcss: [
require('autoprefixer')({
broswers: ['last 5 versions']
})
],
...
}
16、使用绝对路径
var path = require('path'); // nodejs中的path
path.resolve(__dirname, 'app/src'); // 生成绝对路径,
resolve
:解析,
__dirname
:运行环境下的变量即当前环境下的路径
'app/src'
:相对路径
17、处理项目中的css
npm install postcss-loader --save-dev
module.exports = {
...
module: {
loaders: [{
test: /\.css$/,
loader: 'style-loader!css-loader?importLoaders=1!postcss-loader',
// loaders: ['style-loader','css-loader','postcss-loader']
}],
},
post: [
require('autoprefixer')({ // 为css样式加上浏览器前缀
broswers: ['last 5 versions']
})
],
...
}
?importLoaders=1
:为传参,使css文件中通过 @import 引入的css也能被loader插件处理
loader的处理顺序是从右到左。
npm i less-loader --save-dev
18、在模板中使用相对路径的图片
<img src="${ require('../../assets/bg.png') }" />
const path = require('path');
module.exports = {
mode: "production", // "production" | "development" | "none"
entry: "./app/entry", // string | object | array
/* entry: ["./app/entry1", "./app/entry2"],
entry: {
a: "./app/entry-a",
b: ["./app/entry-b1", "./app/entry-b2"]
}, */
// webpack 如何输出结果的相关选项
output: {
// 所有输出文件的目标路径
path: path.resolve(__dirname, "dist"), // 必须是绝对路径(使用 Node.js 的 path 模块)
// 「入口分块(entry chunk)」的文件名模板(出口分块?)
filename: 'bundle.js',
/* filename: '[name].js', // 用于多个入口点(entry point)(出口点?)
filename: '[chunkhash].js', // 用于长效缓存 */
// 输出解析文件的目录,url 相对于 HTML 页面
publicPath: "/assets/", // string
/* publicPath: "",
publicPath: "https://cdn.example.com/", */
// 导出库(exported library)的名称
library: "MyLibrary", // string,
// 导出库(exported library)的类型
libraryTarget: "umd2", // 通用模块定义
libraryTarget: "commonjs2", // exported with module.exports
libraryTarget: "commonjs-module", // 使用 module.exports 导出
libraryTarget: "commonjs", // 作为 exports 的属性导出
libraryTarget: "amd", // 使用 AMD 定义方法来定义
libraryTarget: "this", // 在 this 上设置属性
libraryTarget: "var", // 变量定义于根作用域下
libraryTarget: "assign", // 盲分配(blind assignment)
libraryTarget: "window", // 在 window 对象上设置属性
libraryTarget: "global", // property set to global object
libraryTarget: "jsonp", // jsonp wrapper
// 在生成代码时,引入相关的模块、导出、请求等有帮助的路径信息。
pathinfo: true, // boolean
// 「附加分块(additional chunk)」的文件名模板
chunkFilename: "[id].js",
// chunkFilename: "[chunkhash].js", // 长效缓存(/guides/caching)
// 用于加载分块的 JSONP 函数名
jsonpFunction: "myWebpackJsonp", // string
// 「source map 位置」的文件名模板
sourceMapFilename: "[file].map", // string
// sourceMapFilename: "sourcemaps/[file].map", // string
// 「devtool 中模块」的文件名模板
devtoolModuleFilenameTemplate: "webpack:///[resource-path]", // string
// 「devtool 中模块」的文件名模板(用于冲突)
devtoolFallbackModuleFilenameTemplate: "webpack:///[resource-path]?[hash]", // string
// 在 UMD 库中使用命名的 AMD 模块
umdNamedDefine: true, // boolean
// 指定运行时如何发出跨域请求问题
crossOriginLoading: "use-credentials", // 枚举
// crossOriginLoading: "anonymous",
// crossOriginLoading: false,
},
// 关于模块配置
module: {
// 模块规则(配置 loader、解析器等选项)
rules: [
// test 和 include 具有相同的作用,都是必须匹配选项
// exclude 是必不匹配选项(优先于 test 和 include)
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo-files")
],
// 最佳实践:
// - 只在 test 和 文件名匹配 中使用正则表达式
// - 在 include 和 exclude 中使用绝对路径数组
// - 尽量避免 exclude,更倾向于使用 include
// issuer 条件(导入源)
issuer: { test, include, exclude },
// 标识应用这些规则,即使规则覆盖(高级选项)
enforce: "pre",
// enforce: "post",
// 应该应用的 loader,它相对上下文解析
loader: "babel-loader",
// loader 的可选项
options: {
presets: ["es2015"]
},
},{
test: /\.html$/,
// test: "\.html$"
use: [
// 应用多个 loader 和选项
"htmllint-loader",
{
loader: "html-loader",
options: {
/* ... */
}
}
]
},
// 只使用这些嵌套规则之一
{ oneOf: [ /* rules */ ] },
// 使用所有这些嵌套规则(合并可用条件)
{ rules: [ /* rules */ ] },
// 仅当所有条件都匹配时才匹配
{ resource: { and: [ /* 条件 */ ] } },
// 任意条件匹配时匹配(默认为数组)
{ resource: { or: [ /* 条件 */ ] } },
{ resource: [ /* 条件 */ ] },
// 条件不匹配时匹配
{ resource: { not: /* 条件 */ } }
],
noParse: [
/special-library\.js$/
],
// 不解析这里的模块
unknownContextRequest: ".",
unknownContextRecursive: true,
unknownContextRegExp: /^\.\/.*$/,
unknownContextCritical: true,
exprContextRequest: ".",
exprContextRegExp: /^\.\/.*$/,
exprContextRecursive: true,
exprContextCritical: true,
wrappedContextRegExp: /.*/,
wrappedContextRecursive: true,
wrappedContextCritical: false,
// specifies default behavior for dynamic requests
},
// 解析模块请求的选项
// (不适用于对 loader 解析)
resolve: {
// 用于查找模块的目录
modules: [
"node_modules",
path.resolve(__dirname, "app")
],
// 使用的扩展名
extensions: [".js", ".json", ".jsx", ".css"],
// 模块别名列表
alias: {
// 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file"
"module": "new-module",
// 起别名 "only-module" -> "new-module",但不匹配 "only-module/path/file" -> "new-module/path/file"
"only-module$": "new-module",
// 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误
"module": path.resolve(__dirname, "app/third/module.js"),
// 模块别名相对于当前上下文导入
},
/* 可供选择的别名语法(点击展示) */
alias: [
{
name: "module", // 旧的请求
alias: "new-module", // 新的请求
onlyModule: true // 如果为 true,只有 "module" 是别名,如果为 false,"module/inner/path" 也是别名
}
],
},
performance: {
hints: "warning", // 枚举
// hints: "error", // 性能提示中抛出错误
// hints: false, // 关闭性能提示
maxAssetSize: 200000, // 整数类型(以字节为单位)
maxEntrypointSize: 400000, // 整数类型(以字节为单位)
assetFilter: function(assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
// 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
// 牺牲了构建速度的 `source-map' 是最详细的。
devtool: "source-map", // enum
// devtool: "inline-source-map", // 嵌入到源文件中
// devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中
// devtool: "hidden-source-map", // SourceMap 不在源文件中引用
// devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant)
// devtool: "cheap-module-source-map", // 有模块映射(module mappings)的 SourceMap 低级变体
// devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。
// webpack 的主目录,entry 和 module.rules.loader 选项相对于此目录解析
context: __dirname, // string(绝对路径!)
// 包(bundle)应该运行的环境
// 更改 块加载行为(chunk loading behavior) 和 可用模块(available module)
target: "web", // 枚举
// target: "webworker", // WebWorker
// target: "node", // node.js 通过 require
// target: "async-node", // Node.js 通过 fs and vm
// target: "node-webkit", // nw.js
// target: "electron-main", // electron,主进程(main process)
// target: "electron-renderer", // electron,渲染进程(renderer process)
// target: (compiler) => { /* ... */ }, // 自定义
// 不要遵循/打包这些模块,而是在运行时从环境中请求他们
externals: ["react", /^@angular\//],
/*
externals: "react", // string(精确匹配)
externals: /^[a-z\-]+($|\/)/, // 正则
externals: { // 对象
angular: "this angular", // this["angular"]
react: { // UMD
commonjs: "react",
commonjs2: "react",
amd: "react",
root: "React"
}
},
externals: (request) => { /* ... */ return "commonjs " + request }
*/
// 精确控制要显示的 bundle 信息
stats: "errors-only",
/*
stats: { //object
assets: true,
colors: true,
errors: true,
errorDetails: true,
hash: true,
// ...
},
*/
devServer: {
proxy: { // proxy URLs to backend development server
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
compress: true, // enable gzip compression
historyApiFallback: true, // true for index.html upon 404, object for multiple paths
hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
https: false, // true for self-signed, object for cert authority
noInfo: true, // only errors & warns on hot reload
// ...
},
// 附加插件列表
plugins: [
// ...
],
/*** 高级配置 ***/
// 独立解析选项的 loader
resolveLoader: { /* 等同于 resolve */ }
// 限制并行处理模块的数量
parallelism: 1, // number
// 捕获时机信息
profile: true, // boolean
// 在第一个错误出错时抛出,而不是无视错误。
bail: true, //boolean
// 禁用/启用缓存
cache: false, // boolean
// 启用观察
watch: true, // boolean
watchOptions: {
// 将多个更改聚合到单个重构建(rebuild)
aggregateTimeout: 1000, // in ms
poll: true,
poll: 500, // 间隔单位 ms
// 启用轮询观察模式
// 必须用在不通知更改的文件系统中
// 即 nfs shares(译者注:Network FileSystem,最大的功能就是可以透過網路,讓不同的機器、不同的作業系統、可以彼此分享個別的檔案 ( share file ))
},
// Polyfills and mocks to run Node.js-environment code in non-Node environments.
node: {
console: false, // boolean | "mock"
global: true, // boolean | "mock"
process: true, // boolean
__filename: "mock", // boolean | "mock"
__dirname: "mock", // boolean | "mock"
Buffer: true, // boolean | "mock"
setImmediate: true // boolean | "mock" | "empty"
},
recordsPath: path.resolve(__dirname, "build/records.json"),
recordsInputPath: path.resolve(__dirname, "build/records.json"),
recordsOutputPath: path.resolve(__dirname, "build/records.json"),
// TODO
};