Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack入门 #65

Closed
Wscats opened this issue Feb 18, 2017 · 0 comments
Closed

webpack入门 #65

Wscats opened this issue Feb 18, 2017 · 0 comments
Labels

Comments

@Wscats
Copy link
Owner

Wscats commented Feb 18, 2017

安装 webpack

//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack

这里记得一定要全局安装 webpack,不然无法在命令行执行webpack指令

准备阶段

npm init

执行后会在根目录生成一个package.json的文件
文件目录结构如下:
image

// 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 文件
image

当然你还可以在 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

image

还有注意的是,如果不加下面的代码,在调试代码的时候很可能就找不到行数了

devtool: 'eval-source-map', //用于调试代码

加了之后就会显示未合并之前的文件所在行数
image
未加则显示合并后在 bundle.js 的行数
image

devtool 选项对应的配置结果

  1. source-map:在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的 source map,但是它会减慢打包文件的构建速度
  2. cheap-module-source-map:在一个单独的文件中生成一个不带列映射的 map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便
  3. eval-source-map:使用 eval 打包源文件模块,在同一个文件中生成干净的完整的 source map。这个选项可以在不影响构建速度的前提下生成完整的 sourcemap,但是对打包后输出的 JS 文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项
  4. 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
image
在浏览器打开http://localhost:8080/
就会显示静态页面,如果改动文件,浏览器还会热更新

devserver 配置选项和功能描述

  1. contentBase:默认 webpack-dev-server 会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录)
  2. port:设置默认监听端口,如果省略,默认为”8080“
  3. inline:设置为 true,当源文件改变时会自动刷新页面
  4. colors:设置为 true,使终端输出的文件为彩色的
  5. 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

exportexport 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环境进行配置
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant