写在前面
上一篇博客,我们详细说了模块化的历史,不使用webpack的坏处,webpack的作用,以及怎么安装,配置webpack,配置webpack是在webpack.config.js文件中完成的
五、使用webpack
有三种方式运行webpack
1. 执行 npx webpack,会将我们的脚本作为入口起点,然后 输出 为 main.js。Node 8.2+ 版本提供的 npx 命令,可以运行在初始安装的 webpack 包(package)的 webpack 二进制文件(./node_modules/.bin/webpack)
2. 输入./node_modules/.bin/webpack
3. 用 CLI 这种方式来运行本地的 webpack 不是特别方便,我们可以设置一个快捷方式。在package.json添加一个 npm 脚本(npm script),package.json里的命令和npx类似自动在相应目录下查找
"scripts": {
"webpack"
} 现在,可以使用 npm run build 命令,来替代我们之前使用的 npx 命令。
注意现在我们的文件结构
webpack-demo
|- package.json
|- /dist
|- index.html
|- /src
|- index.js我们把src里的index.js,打包至dist目录下的main.js(webpack.config.js里规定的entry和output),我们需要在dist目录下创建一个index.html,而且index.html需要引用main.js,而不是index.html,这样很不方便下面我们解决这个问题,并且使用hash值作为output的文件名
六、index.html的引用问题
var path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
},但是这样会导致每次 npm run build 就会产生一个新的buddle
我们可以修改package.json里的script,来同时完成删除旧的生成新的
"scripts": {
"build": "rm -rf dist && webpack"
} 七、插播HTTP缓存(哈希名字的目的)
举个例子,比如我们访问一个网站,需要下载HTML以及很多CSS,图片,JS等等文件,很慢,下次我们访问该网站时候,我们首先下载HTML,然后就会在内存和硬盘里查找附属的文件,那么就会有下面疑问?
1. index.hmtl必须要下载吗?
2. 网站更新怎么办?
3. 怎么设置缓存?
我们可以在响应头里设置 cache .control:public, max-age-31536000,那么网站就可以缓存了
如果网站更新,那么新buddle的哈希文件名也会改变,所以只有内容不一样,文件名也不一样,
结合上一点就可以回答index.html不缓存了,如果index.html缓存了,那么就无法得知是否更新了,只能等待缓存失效,
八、自动生成HTML
上面我们讲的都是输入一个js文件,根据依赖输出一个js文件,而且我们必须手动在dist目录下创建html,手动引入,但是我们使用哈希文件名就破裂了
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
},
plugins: [new HtmlWebpackPlugin()]};九、引入CSS
上面我们解决了JS和HTML,现在我们解决CSS
模块化css,我们通常把import或者require xxx.css放在js文件中,如果没有做任何设置,那么webpack遇到css后缀就会报错,我们使用loader来打包模块化的css后缀文件
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: ['style-loader','css-loader'] }
]
}
};“嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.css' 的路径」时,在你对它打包之前,先用css-loader 把css文件读到js里面。然后再使用style-loader 把它插到head的style标签里面”
十、webpack-dev-serve
npm install --save-dev webpack-dev-serverwebpack.config.js修改配置文件,告诉开发服务器(dev server),在哪里查找文件:
module.exports = {
devServer: {
contentBase: './dist'
}
}以上配置告知 webpack-dev-server,在 localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。
package.json让我们添加一个 script 脚本,可以直接运行开发服务器(dev server):
"scripts": {
"start": "webpack-dev-server --open", //open指打开浏览器
},webpack-dev-serve是不生成dist的
十一、抽出CSS文件
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
}它会将所有的入口 chunk(entry chunks)中引用的 *.css,移动到独立分离的 CSS 文件。因此,你的样式将不再内嵌到 JS bundle 中,而是会放到一个单独的 CSS 文件(即 styles.css)当中。 如果你的样式文件大小较大,这会做更快提前加载,因为 CSS bundle 会跟 JS bundle 并行加载。
new ExtractTextPlugin(options: filename | object)
生成文件的文件名。可能包含 [name], [id] and [contenthash]
警告:ExtractTextPlugin对 每个入口 chunk 都生成一个对应的文件,所以当你配置多个入口 chunk 的时候,你必须使用[name],[id]或[contenthash],
十二、两种webpack.config.js
创建两个webpack.config.js,一个开发时用用loader且不用hash,另一个生产时候用css extract以及hash,
"scripts": {
"build": "rm -rf dist && webpack" --config webpack.connfig.xxx.json
} 这样即可
我们甚至看用继承的思想,因为两个json文件大部分都一样,创建一个新的json文件,再require进来即可
const base = require( './webpack. config.base.js')
module.exports = {
...base,
devServer: {
contentBase:"./dist"
}
module: {
rules: [
{
test: /\.css$/i ,
use: ["style-loader", "css-loader"]
}
]
}
}; ...base把base所有东西都抄过来,然后下面在进行覆盖,这样很容易有bug,比如module一不小心把base里的全都覆盖了
const base = require( './webpack. config.base.js')
module.exports = {
...base,
devServer: {
contentBase:"./dist"
}
module: {
...base.module
rules: [
{
test: /\.css$/i ,
use: ["style-loader", "css-loader"]
}
]
}
}; 正确应该上面代码做
也可以if else写入一个文件中
package.json
{
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
// ...
}webpack.config.js
var path = require('path');
var merge = require('webpack-merge');
var TARGET = process.env.npm_lifecycle_event;
var common = {
entry: path.join(__dirname, 'app'),
...
module: {
loaders: [
{
test: /\.css$/,
loaders: ['style', 'css'],
},
],
},
};
if(TARGET === 'start') {
module.exports = merge(common, {
module: {
// loaders will get concatenated!
loaders: [
{
test: /\.jsx?$/,
loader: 'babel?stage=1',
include: path.join(ROOT_PATH, 'app'),
},
],
},
...
});
}
if(TARGET === 'build') {
module.exports = merge(common, {
...
});
}
...