webpack入门
Wscats opened this issue · 0 comments
安装 webpack
//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack
这里记得一定要全局安装 webpack,不然无法在命令行执行webpack指令
准备阶段
npm init
执行后会在根目录生成一个package.json的文件
文件目录结构如下:
// Greeter.js
module.exports = function () {
var greet = document.createElement("div");
greet.textContent = "Hi there and greetings!";
console.log("test");
return greet;
};
//main.js
var greeter = require("./Greeter.js");
document.getElementById("root").appendChild(greeter());
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id='root'>
</div>
<script src="bundle.js"></script>
</body>
</html>
//webpack.config.js
module.exports = {
//devtool: 'eval-source-map', //用于调试代码
entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方
filename: "bundle.js", //打包后输出文件的文件名
},
};
3.执行命令打包
当我们在根目录下有上面写好完整的webpack.config.js之后,我们可以在命令行执行webpack执行打包,如果成功就会在 public 文件夹生成一个 bundle.js 文件
当然你还可以在 package.json 自己定义好一个执行命令来代替这些繁琐的命令,例如
//package.json
{
"name": "wscat-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"webpack": "^1.14.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack"
},
"author": "",
"license": "ISC"
}
加上这句之后
"start": "webpack" //配置的地方就是这里啦,相当于把npm的start命令指向webpack命令
你就可以执行npn run start
还有注意的是,如果不加下面的代码,在调试代码的时候很可能就找不到行数了
devtool: 'eval-source-map', //用于调试代码
加了之后就会显示未合并之前的文件所在行数
未加则显示合并后在 bundle.js 的行数
devtool 选项对应的配置结果
- source-map:在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的 source map,但是它会减慢打包文件的构建速度
- cheap-module-source-map:在一个单独的文件中生成一个不带列映射的 map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便
- eval-source-map:使用 eval 打包源文件模块,在同一个文件中生成干净的完整的 source map。这个选项可以在不影响构建速度的前提下生成完整的 sourcemap,但是对打包后输出的 JS 文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项
- cheap-module-eval-source-map:这是在打包文件时最快的生成 source map 的方法,生成的 Source Map 会和打包后的 JavaScript 文件同行显示,没有列映射,和 eval-source-map 选项具有相似的缺点
上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的构建速度的后果就是对打包后的文件的的执行有一定影响
配置服务器
npm install -g webpack-dev-server
npm install --save-dev webpack-dev-server
向webpack.config.js文件添加配置项
module.exports = {
devtool: "eval-source-map", //用于调试代码
entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方
filename: "bundle.js", //打包后输出文件的文件名
},
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
//port 设置默认监听端口,如果省略,默认为”8080“
inline: true, //实时刷新
},
};
然后在命令行执行webpack-dev-server
在浏览器打开http://localhost:8080/
就会显示静态页面,如果改动文件,浏览器还会热更新
devserver 配置选项和功能描述
- contentBase:默认 webpack-dev-server 会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录)
- port:设置默认监听端口,如果省略,默认为”8080“
- inline:设置为 true,当源文件改变时会自动刷新页面
- colors:设置为 true,使终端输出的文件为彩色的
- historyApiFallback:在开发单页应用时非常有用,它依赖于 HTML5 history API,如果设置为 true,所有的跳转将指向 index.html
loader
css-loader
webpack 提供两个工具处理样式表,css-loader 和 style-loader,二者处理的任务不同
css-loader使你能够使用类似@import 和 url(...)的方法实现 require()的功能
style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入 webpack 打包后的 JS 文件中
npm install --save-dev style-loader css-loader
然后我们就可以在webpack.config.js文件里面添加这个 loader 的配置项
注意的是style-loader
必须在css-loader
之前引入
module.exports = {
devtool: "eval-source-map", //用于调试代码
entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方
filename: "bundle.js", //打包后输出文件的文件名
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader",
},
],
},
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true, //实时刷新
},
};
"-loader"其实是可以省略不写的,多个 loader 之间用“!”连接起来
/*main.css*/
p{
color: red;
}
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id='root'>
</div>
<p>hello</p>
<script src="bundle.js"></script>
</body>
</html>
此时我们就可以在 main.js 里面直接引进main.css,那所有样式都会打包成 js,在项目运行的时候会转化为**<style>**标签自动引进原页面中
webpack 只有单一的入口,其它的模块需要通过import,require,url等导入相关位置,为了让 webpack 能找到”main.css“文件,我们把它导入”main.js “中
//main.js
var greeter = require("./Greeter.js");
require("./main.css");
document.getElementById("root").appendChild(greeter());
url-loader
还可以对图片进行打包,用这个还要先安装
module.exports = {
devtool: "eval-source-map", //用于调试代码
entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方
filename: "bundle.js", //打包后输出文件的文件名
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader",
},
{
test: /\.(png|jpg)$/,
loader: "url-loader?limit=8192",
},
],
},
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true, //实时刷新
},
};
配置信息的参数“?limit=8192”表示将所有小于 8kb 的图片都转为 base64 形式(其实应该说超过 8kb 的才使用 url-loader 来映射到文件,否则转为 data url 形式)
//main.js
var img1 = document.createElement("img");
img1.src = require("./logo.png");
document.body.appendChild(img1);
babel-loader
webpack 中 babel-loader 转译 ES2015
安装babel-loader,现在我们就可以放心的用 ES6 的语法了
npm install --save-dev babel-loader
npm install --save-dev babel-core babel-preset-es2015 //安装babel 实现 ES6 到 ES5
在 webpack.config.js 中添加配置项
module: {
loaders: [ {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
}]
},
//ES6转ES5
babel: {
presets: ['es2015']
},
// Greeter.js
module.exports = function () {
var greet = document.createElement("div");
greet.textContent = "Hi there and greetings!";
console.log("test2");
return greet;
};
可以把上面的代码用 ES6 改写成下面的格式
// Greeter.js
export default function f() {
var greet = document.createElement("div");
greet.textContent = "Hi there and greetings!";
console.log("test2");
return greet;
}
var greeter = require("./Greeter.js"); //ES5
import greeter from "./Greeter.js"; //ES6
export与export default均可用于导出常量、函数、文件、模块等,你可以在其它文件或模块中通过 import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用,但在一个文件或模块中,export、import 可以有多个,export default 仅有一个
所以上面是只导出一个函数的情况,如果导出多个可以用下面这种方式
// test.js
export const str = "hello world";
export function f(a) {
return a + 1;
}
import { str, f } from "./test.js";
react 下的 babel-loader
在 react 下需要以下几个重要的 babel 文件
模块 | 作用 |
---|---|
babel-core | babel-core 的作用是把 js 代码分析成 ast,方便各个插件分析语法进行相应的处理,比如有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为 ast,分析其语法后再转为低版本 js |
babel-loader | |
babel-preset-env/babel-preset-2015/babel-preset-latest | 现代的浏览器大多支持 ES6 的 generator,但是如果你使用 babel-preset-es2015,它会将 generator 函数编译为复杂的 ES5 代码,这是没有必要的。但使用 babel-preset-env,我们可以声明环境,然后该 preset 就会只编译包含我们所声明环境缺少的特性的代码,因此也是比较推荐的方式 |
babel-preset-react | jsx 是需要编译才能被浏览器识别的,它就是被 Babel 编译的,具体说来是被 babel-preset-react 来编译的 |
.babelrc文件需要添加react
{
"presets": ["react", "env"]
}
webpack.config.js下的配置可以写成这样
module: {
rules: [
{
test: /\.js[x]?$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
},
},
];
}
或者不写.babelrc 文件直接在 webpack.config.js 下这样配置,就是等同于把.babelrc 下的配置换成在 query 参数中配置
module: {
rules: [
{
test: /\.js[x]?$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
query: {
presets: ["env", "react"],
},
},
},
];
}
vue-loader
vue-loader 能够把我们的组件.vue 文件转化为 js 加载到我们项目中
<!-- app.vue-->
<template>
<div>{{msg}}</div>
</template>
<script>
export default {
data() {
return {
msg: 'Hello from vue-loader!'
}
},
}
</script>
<style>
div {
color: red;
}
</style>
这里面要注意的是 vue2 开始要用render: (createElement) => createElement(App)
来注册组件,components 在 vue1 才能使用了,当然在组件.vue 文件里面注册组件还是可以用 components,
还有需要注意的是 vue2 之后不能在 el 为 body 和 html 节点上添加组件,所以我这里改成el: '#app'
var Vue = require("vue");
var App = require("./app.vue");
//import App from './app.vue'
new Vue({
el: "#app",
render: (createElement) => createElement(App),
/*components: {
app: App
}*/
});
webpack.config.js 要添加 resolve 和 vue-loader
//webpack.config.js
module.exports = {
devtool: "eval-source-map", //用于调试代码
entry: __dirname + "/app/abc.js", //已多次提及的唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方
filename: "bundle.js", //打包后输出文件的文件名
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader",
},
{
test: /\.(png|jpg)$/,
loader: "url-loader?limit=8192",
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.vue$/,
loader: "vue-loader",
},
],
},
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true, //实时刷新
},
resolve: {
alias: {
vue: "vue/dist/vue.js",
},
},
};
file-loader
webpack 加载 css 文件中的 eot,ttf 等格式
可以用来处理 ttf 格式等文件
需要先安装 file-loader
npm install file-loader
然后配置加载器
{
test: /\.eot/,
loader: 'file-loader?prefix=font/'
}, {
test: /\.woff/,
loader: 'file-loader?prefix=font/&limit=10000&mimetype=application/font-woff'
}, {
test: /\.ttf/,
loader: 'file-loader?prefix=font/'
}, {
test: /\.svg/,
loader: 'file-loader?prefix=font/'
}
sass-loader
安装两个模块
npm install sass-loader node-sass
编写 sass 格式的文件
<style scope lang="scss">
$size: 20px;
p{
font-size: $size;
}
</style>
配置 webpack.config.js 文件
{
test: /\.scss/,
loader: 'sass-loader'
}
less-loader
npm install less,less-loader --save-dev
在webpack.config.js修改:
module: {
loaders: [{ test: /\.less$/, loader: "style-loader!css-loader!less-loader" }];
}
在 module 的 loaders 中,增加了!less-loader
如此便可以在 js 中,require .less 文件
html-webpack-plugin
- 自动为 html 文件中引入的外部资源如
script、link
动态添加每次编译后的哈希值,防止引用缓存的外部文件问题 - 自动生成创建 html 入口文件,比如单页面可以生成一个 html 文件入口,配置 N 个
html-webpack-plugin
可以生成 N 个页面入口
module.exports = {
//code...
output: {
path: __dirname + "/dist",
//注意这里输出的是[name],配合后面的hash: true设置
filename: "[name].js",
},
plugins: [
//自动生成index.html
new HtmlWebpackPlugin({
//可以接受一个模板,支持ejs和jade等
//template: 'src/index.html',
hash: true,
}),
],
};
uglify-js-plugin
webpack 自带了压缩 JS 的插件,配置如下
var webpack = require("webpack");
// 插件
plugins: [
// 压缩JS文件
// new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
sourceMap: true,
}),
];
DefinePlugin
有时候我们想在 webpack 全局里面定义一个变量,比如用来区分生产环境和开发环境,公共参数和版本号等,我们就可以通过 DefinePlugin 来实现
new webpack.DefinePlugin({
__DEV__: true,
});
然后在我们代码里面就可以
__DEV__ ? require("A.js") : require("B.js");
其他问题
打包出现以下问题,那是因为一些第三方包用 ES6 语法,在压缩的时候出问题了
Unexpected token: punc (()
解决问题很简单,在根目录下新建.babelrc
文件进行以下配置,看 webpack 的情况而定,可以配置转 ES5
{
"presets": ["env"]
//"presets": ["es2015"]//看babel环境进行配置
}