webpack配置
文章中以 $ 符号开头的是在终端输入的命令
文章中以 vim 开头为编辑文件内容
从零开始
$ mkdir dailypaper
新建一个项目文件夹dailypaper
$ npm init
在该文件夹下npm init初始化项目文件夹会产生package.json文件
$ npm install -D webpack
本地局域安装webpack依赖
$ npm install -D webpack-dev-server
开发环境安装服务器热更新依赖
$ mkdir app
创建app文件夹用来存放放原始代码文件
$ mkdir public
创建public文件夹用来存放打包后的文件
$ touch webpack.config.js
创建web pack.config.js 配置文件
webpack.config.js配置文件四大重要组成部分:入口文件、出口文件、loader、插件plugins
vim web pack.config.js 初始化webpack.config.js的内容
var config = {
};
module.exports = config;
这里的module.exports = config;相当于export default config;。由于目前还没有安装支持ES6的编译插件,因此不能直接用ES6的语法,否则会报错。
vim package.json 的scripts里添加快速启动热更新服务的脚本
{
//…
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open --config webpack.config.js",
},
//…
}
当运行 npm run dev时,就会执行”webpack-dev-server –open –config webpack.config.js”命令,其中—config 是指向 webpack-dev-server 读取的配置文件路径,即之前创建的 webpack.config.js 文件。—open会在执行命令时自动在浏览器打开页面,默认地址为127.0.0.1:8080,不过IP和端口都是可以配置的,如:
vim package.json
"scripts": {
"dev": "webpack-dev-server —-host 172.172.172.1 —-port 8888 —-open --config webpack.config.js",
},
一般在局域网中,需要其他同事访问时可以这样设置,否则默认就可以
入口出口配置
Webpack配置 最重要的是两项配置入口(Entry)和出口(Output),在dailypaper文件夹下新建一个空的app.js作为入口的文件,再进行
在dailypaper文件下
$ touch app.js
新建app.js文件
vim web pack.config.js中
var path = require('path');
var config = {
entry: {
app: './app.js'
},
output: {
path: path.join(__dirname,'./public'),
publicPath: '/public/',
filename: 'main.js',
},
};
module.exports = config;
entry中的main是单入口,webpack会从main.js文件开始工作, output中path选项用来存放打包后的文件输出目录,是必填项。 publicPath指定资源文件引用的目录,如果你的资源文件放在CDN上,可填CDN的网址。filename用于指定输出文件的名称。因此,这里配置的output意为打包后的文件会存储为daily/public/main.js文件,只要在html中引入它就可以了。
在dailypaper文件下
$ touch index.html
新建index.html文件
- vim index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dailypaper</title>
</head>
<body>
<div id="app">
Hello World
</div>
<script src="./public/main.js"></script>
</body>
</html>
然后就可以执行以下命令了:
$ npm run dev
就能打开网页显示Hello World了
vim app.js 打开dailypaper文件夹下的app.js,添加一行代码
document.getElementById('app').innerHTML = 'Hello webpack.';
此时页面已经自动变成了Hello webpack.
此时看浏览器开发者工具的network视图中(刷新页面)的main.js有几千行代码,这是在开发环境下,大多都是webpack-dev-server的功能,只在开发时有效,在生产环境下编译就不会这么臃肿,执行以下命令打包
$ webpack —progress —hide-modules 打包 没有压缩
这时public 下的main.js就只有几十行
loader配置
webpack配置除了入口和出口,需要进一步配置来实现更强大的功能
每个文件都是一个模块,不同的模块需要不同的加载器loaders来处理,加载器是webpack最重要的功能,通过安装不同的加载器可以对各种后缀名的文件进行处理,比如CSS样式需要用到 style-loaderloader和 css-loader
$ install css-loader style-loader -D
安装完成后再在webpack.config.js中配置Loader,增加对css文件的处理
vim web pack.config.js
var path = require('path');
var config = {
entry: {
app: './app'
},
output: {
path: path.join(__dirname,'./public'),
publicPath: '/public/',
filename: 'main.js'
},
module: {
rules: [
{
test:/\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
};
module.exports = config;
在 module 对象中的 rules 属性中可以指定一系列的 loaders ,每一个 loader 必须包含 test 和 use 两个选项,
以上意思是,当遇到后缀名为.css的文件时,先将它通过 css-loader 转换,再通过 style-loader 转换,然后继续打包,use的值可以是字符串或者数组,如果是数组,它的编译顺序是从后往前。
dailypaper文件夹下
$ touch style.css
新建style.css,并在app.js中导入
vim style.css
#app {
font-size:24px;
color:#f50;
}
vim 在app.js中
import './style.css’; //配置了loader之后,就可以直接这么将样式文件通过import引入js 文件中
document.getElementById('app').innerHTML = 'Hello webpack.';
插件配置
CSS是通过JS动态创建 style 标签来写入的, 这意味着代码已经编译在了main.js中,但在实际业务中,样式文件会很多,都放在JS里太占体积,还不能做缓存。这时候需要用到另一个重要——插件(Plugin)
这里可以使用一个 extract-text-webpack-plugin 的插件来将散落在各地的CSS提取出来,并生成一个main.css文件,最终在index.html里通过 的形式加载。
$ npm install extract-text-webpack-plugin -D
然后在配置文件中导入插件,并改写loader的配置
vim web pack.config.js
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
entry: {
app: './app'
},
output: {
path: path.join(__dirname,'./public'),
publicPath: '/public/',
filename: 'main.js'
},
module: {
rules: [
{
test:/\.css$/,
// use: [
// 'style-loader',
// 'css-loader'
// ]
use: ExtractTextPlugin.extract({
use: 'css-loader',
fallback:'style-loader'
})
}
]
},
plugins:[
//重命名提取后的CSS文件,此时必须要在index.html中引用才会有样式效果,打包成一个main.css
new ExtractTextPlugin("main.css")
]
};
module.exports = config;
vim Index.html 必须要使用 link 标签来引用才会有样式展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dailypaper</title>
<link rel="stylesheet" type="text-css" href="/public/main.css">
</head>
<body>
<div id="app">
Hello World
</div>
<script src="/public/main.js"></script>
</body>
</html>
进阶配置
引入 .vue 单文件与Vue-loader
.vue单文件组件需要使用 vue-loader 转换处理
一个 .vue 文件包括 template script style 三部分
$ touch app.vue
app 文件夹下 新建 app.vue
vim app.vue
<template>
<div> 你好,单文件组件</div>
</template>
<script>
export default {
}
</script>
<style scoped >
div {
color:red;
}
</style>
scoped 表示当前的CSS只在当前组件内有效,如果不加,会应用到整个项目,lang=‘less’ 表示使用 less 预编译处理
使用 .vue 文件需要先安装 vue-loader vue-style-loader 等加载器并做配置
另外要使用ES6语法,需要安装 babel 和 babel-loader 等加载器。
$ npm install -S vue
$ npm install -D vue-loader
$ npm install -D vue-style-loader
$ npm install -D vue-template-compiler
$ npm install -D vue-hot-reload-api
$ npm install -D babel
$ npm install -D babel-loader
$ npm install -D babel-core
$ npm install -D babel-plugin-transform-runtime
$ npm install -D babel-preset-es2015
$ npm install -D babel-runtime
安装完成后,添加配置
vim webpack.config.js 来支持对 .vue 以及 ES6 的解析;
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
entry: {
app: './app'
},
output: {
path: path.join(__dirname,'./public'),
publicPath: '/public/',
filename: 'main.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader:'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use:'css-loader',
fallback:'vue-style-loader'
})
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test:/\.css$/,
// use: [
// 'style-loader',
// 'css-loader'
// ]
use: ExtractTextPlugin.extract({
use: 'css-loader',
fallback:'style-loader'
})
}
]
},
plugins:[
//重命名提取后的CSS文件
new ExtractTextPlugin("main.css")
]
};
module.exports = config;
vue-loader 在编译 .vue 文件时,会对
// document.getElementById('app').innerHTML = 'Hello webpack.’;
import './style.css';
import App from './app/app.vue';
import Vue from 'vue';
new Vue({
el: '#app',
render: h => h(App) //这里不能直接写为components: { App },template:’<App></App>’,会报错
})
然后就可以
$ npm run dev 在浏览器中可以看到app.vue组件的内容替换了index.html 中的 id =‘app' 的 div
生产环境
进一步配置webpack
安装 url-loader file-loader 来支持图片、字体等文件;
$ npm install url-loader file-loader -D
vim webpack.config.js
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
entry: {
app: './app'
},
output: {
path: path.join(__dirname,'./public'),
publicPath: '/public/',
filename: 'main.js'
},
module: {
rules: [
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader?limit=1024'
},
{
test: /\.vue$/,
loader:'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use:'css-loader',
fallback:'vue-style-loader'
})
},
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test:/\.css$/,
// use: [
// 'style-loader',
// 'css-loader'
// ]
use: ExtractTextPlugin.extract({
use: 'css-loader',
fallback:'style-loader'
})
}
]
},
plugins:[
//重命名提取后的CSS文件
new ExtractTextPlugin("main.css")
]
};
module.exports = config;
当遇到 .gif .png .ttf 等格式文件时,url-loader 会把它们一起编译到 public 目录下, “?limit=1024”是指如果这个文件小于1kb,就以base64 的形式加载,不会生成一个文件。
在app.vue 中加载一个图片。
vim app.vue
<template>
<div>
<h1>你好,单文件组件</h1>
<p>
nice to see you!
</p>
<img src="./img/snow.jpg" width="300">
</div>
</template>
<script>
export default {
name:'app',
data(){
return {
}
}
}
</script>
<style scoped lang='less'>
div {
color:red;
p {
color:blue;
}
}
</style>
打包上线
打包后的产物:
单页面富应用(SPA)最终只有一个html 文件,其余都是静态资源,实际部署到生产环境时,一般会将html 挂在后端程序下,由后端路由渲染这个页面,将所有的静态资源(CSS JS、image、iconfont等)单独部署到CDN,当然也可以和后端程序部署在一起,这样就实现了前后端完全分离。
我们在webpack 的output 选项里已经指定了path 和publicPath ,打完包后,所有的资源都会在dailypaper/public 目录下。
下面是两个打包会用到的依赖, 使用NPM 安装
$ npm install webpack-merge -D
$ npm html-webpack-plugin -D
为了方便开发和生产环境的切换,我们在 dailypaper 目录下再建一个用于生产环境的配置文件 webpack.prod.config.js
vim webpack.prod.config.js
var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var merge = require('webpack-merge');
var webpackBaseConfig = require('./webpack.config.js');
//清空基本配置的插件列表
webpackBaseConfig.plugins=[];
module.exports=merge(webpackBaseConfig,{
output: {
publicPath: '/public_CDN/',
//将入口文件重命名为带有20位hash值的唯一文件
filename: 'static/js/[name].[hash].js' //filename定义的路径就在打包配置的public文件夹下
},
plugins: [
new ExtractTextPlugin({
//提取CSS, 并重命名为带有20位hash值的唯一文件
filename: 'static/css/[name].[hash].css',
allChunks: true
}),
//定义当前的code 环境为生产环境
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
//压缩 JS
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
//提取模板,并保存入口html文件
new HtmlwebpackPlugin({
filename: 'index_prod.html',//在public文件夹下,index_prod.html与static在同一目录下,
template: './index.ejs',
inject: false
})
]
})
其中/public_CDN/需要修改为部署存放static文件夹的CDN服务器地址。
上面安装的web pack-merge 模块就是用于合并两个webpack的配置文件,所以prod的配置是在web pack_config.js的基础上扩展的,静态资源大部分场景下都有缓存(304),更新上线后一般都希望用户能及时地看到内容,所以给打包后的CSS和JS文件的名称都加了20位的hash值,这样文件名就唯一了,只要不对html 设置缓存,上线后就能加载最新的静态资源。
Html-webpack-plugin 是用来生成 .html 文件的, 它通过 template 选项来读取指定的模板 index.ejs, 然后输出到 filename 指定的目录, 也就是 public/index_prod.html。
下面是模板 index.ejs 动态设置了静态资源的路径和文件名 该文件在dailypaper目录下
vim index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dailypaper</title>
<link rel="stylesheet" type="text-css" href="<%= htmlWebpackPlugin.files.css[0] %>">
</head>
<body>
<div id="app">
</div>
<script type='text/javascript' src="<%= htmlWebpackPlugin.files.js[0] %>"></script>
</body>
</html>
ejs 是一个JavaScript 模板库,用来从JSON 数据中生成HTML 字符串, 常用语Node.js
vim webpack.config.js
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
entry: {
app: './app'
},
output: {
path: path.join(__dirname, './public/'),
publicPath: '/public/‘,
filename: 'main.js'
},
module: {
rules: [{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader?limit=1024&name=images/[hash:8].[name].[ext]’ //打包多个图片时
//name 字段指定了在打包根目录(output.path)下生成名为 images 的文件夹,并在原图片名前加上8位 hash 值
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
},
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
// use: [
// 'style-loader',
// 'css-loader'
// ]
use: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'style-loader'
})
}
]
},
plugins: [
//重命名提取后的CSS文件
new ExtractTextPlugin("main.css")
]
};
module.exports = config;
$ npm run build //打包
此时打包后的 index_prod.html在public 文件夹下,打包后的代码如下所示
打包之后的Index_prod.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dailypaper</title>
<link rel="stylesheet" type="text-css" href="/public_CDN/static/css/app.ba3073bb7bb28cda7d30.css">
</head>
<body>
<div id="app">
</div>
<script type='text/javascript' src="/public_CDN/static/js/app.ba3073bb7bb28cda7d30.js"></script>
</body>
</html>
打包之后的目录如下
下一篇: 刘备为何不能学习其祖先刘邦的避战政策呢?