刚接触webpack,在网上看了些入门的教程和资料,在此作下记录。
什么是webpack?
简单说就是模块加载器,本文不作过多的介绍。
安装webpack
首先确保你的机器已经安装了Node.js和npm(安装方式请参考其他相关资料)。
第一步,为你的项目新建一个文件夹,然后输入 npm init
,然后填写相关问题。
这样会为你创建了 package.json。
第二步,接下来我们安装 Webpack,我们要把它安装在本地,输入 npm i webpack --save-dev
到此就完成了webpack的安装了。
项目目录
/app
main.js
component.js/build
bundle.js (自动创建)
index.html
package.json
webpack.config.js
我们会使用 Webpack 在我们的 /app 里来自动创建 bundle.js 。接下来,我们来设置 webpack.config.js。
设置webpack
webpack.config.js文件设置
var path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'app/main.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
};
按上述项目目录时,__dirname可写为”
运行一个HelloWorld demo
经过上述的配置,我们已经有了一个最简单的配置了,下面我们用它来编译一个简单的Hello World。
app/component.js
'use strict';
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hello world';
return element;
};
app/main.js
'use strict';
var component = require('./component.js');
document.body.appendChild(component());
然后在你的命令行运行 webpack
,接着你可以看到应用会开始编译,一个 bundle.js 文件会这样出现在 /build 文件夹下。
build/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
我们在index.html中引入刚才编译好的bundle.js,我们可以打开 index.html,在浏览器中预览一下效果。
设置 package.json scripts
npm
是一个非常好用的用来编译的指令,通过 npm
你可以不用去担心项目中使用了什么技术,你只要调用这个指令就可以了,只要你在 package.json
中设置 scripts
的值就可以了。
接下来我们把编译通过 npm run build
来执行:
把下面的内容添加到 package.json
中。
"scripts": {
"build": "webpack"
}
现在你可以输入 npm run build
就可以编译了。
开始工作流
每次编译都需要输入npm run build
,想必大家都不愿意,下面我们使用webpack-dev-server
在每次文件改变后自动执行编译。
设置webpack-dev-server
第一步需要安装webpack-dev-server
,在命令行中输入 npm i webpack-dev-server --save
,安装完成后我们需要调整package.json
的scripts
部分去包含这个指令。
package.json
{
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"
}
}
配置完成后,我们可以在命令行里运行 npm run dev
,运行的时候他会执行 dev 属性里的值。编译完成后,我们可以访问“http://localhost:8080” 看到效果。
上述配置顶的意义:
1、webpack-dev-server – 在 localhost:8080 建立一个 Web 服务器
3、devtool eval – 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
4、progress – 显示合并代码进度
5、colors – 命令行中显示颜色!
6、content-base build – 指向设置的输出目录
让浏览器自动刷新
当运行 webpack-dev-server
的时候,它会监听你的文件修改。当项目重新合并之后,会通知浏览器刷新。为了能够触发这样的行为,你需要把你的 index.html 放到 build/ 文件夹下,然后做这样的修改:
build/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<script src="http://localhost:8080/webpack-dev-server.js"></script>
<script src="bundle.js"></script>
</body>
</html>
我们需要增加一个脚本当发生改动的时候去自动刷新应用,你需要在配置中增加一个入口点。
var path = require('path');
module.exports = {
entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
};
按上述目录时,__dirname可设置为”
就是这样!现在你的应用就可以在文件修改之后自动刷新了。
模块
Webpack 允许你使用不同的模块类型,但是 “底层”必须使用同一种实现。所有的模块可以直接在盒外运行。
ES6 模块
import MyModule from './MyModule.js';
CommonJS
var MyModule = require('./MyModule.js');
AMD
define(['./MyModule.js'], function (MyModule) {
});
理解文件路径
一个模块需要用它的文件路径来加载,看一下下面的这个结构:
–app
——modules
———–MyModule.js
——main.js (entry point)
——utils.js
打开 main.js 然后可以通过下面两种方式引入 app/modules/MyModule.js
app/main.js
// ES6
import MyModule from './modules/MyModule.js';
// CommonJS
var MyModule = require('./modules/MyModule.js');
最开始的 ./
是 “相对当前文件路径”
让我们打开 MyModule.js 然后引入 app/utils:
app/modules/MyModule.js
// ES6 相对路径
import utils from './../utils.js';
// ES6 绝对路径
import utils from '/utils.js';
// CommonJS 相对路径
var utils = require('./../utils.js');
// CommonJS 绝对路径
var utils = require('/utils.js');
相对路径是相对当前目录。绝对路径是相对入口文件,这个案例中是 main.js。
安装ReactJs
在命令行在输入npm install react --save
在代码中使用 ReactJS
component.jsx
import React from 'react';
export default class Hello extends React.Component {
render() {
return <h1>Hello world</h1>;
}
}
main.js
import React from 'react';
import Hello from './component.jsx';
main();
function main() {
React.render(<Hello />, document.getElementById('app'));
}
build/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<div id="app"></div>
<script src="http://localhost:8080/webpack-dev-server.js"></script>
<script src="bundle.js"></script>
</body>
</html>
转换 JSX
为了能够使用 JSX 语法,你需要用 Webpack 来转码你的 JavaScript,这是加载器的工作,我们可以使用一个很好用也有很多功能的 Babel。
npm install babel-loader --save-dev
现在我们需要去配置 Webpack 来使用加载器。
webpack.config.js
var path = require('path');
var config = {
entry: ['webpack/hot/dev-server', path.resolve('', 'app/main.js')],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.jsx?$/, // 用正则来匹配文件路径,这段意思是匹配 js 或者 jsx
loader: 'babel' // 加载模块 "babel" 是 "babel-loader" 的缩写
}]
}
};
module.exports = config;
在命令行中运行 npm run dev
,然后刷新页面就可以看到修改。
优化重合并
你可能注意到在引入 React JS 到你的项目之后,给你的应用重新合并会花费太多的时间。在开发环境中,最理想的是编译最多 200 到 800 毫秒的速度,取决于你在开发的应用。
在开发环境中使用压缩文件
为了不让 Webpack 去遍历 React JS 及其依赖,你可以在开发中重写它的行为。
webpack.config.js
var path = require('path');
var node_modules = path.resolve(__dirname, 'node_modules');
var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
config = {
entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
resolve: {
alias: {
'react': pathToReact
}
},
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'babel'
}],
noParse: [pathToReact]
}
};
module.exports = config;
我们在配置中做了两件事:
1、不管 “React” 是什么时候在代码中引入的,它会去匹配压缩后的 React JS 文件取代去 node_modules 中遍历。
2、不管 Webpack 什么时候试图是解析压缩文件,我们阻止它,告诉它那不是必须的。
加载CSS
Webpack允许像加载任何代码一样加载 CSS。你可以选择你所需要的方式,但是你可以为每个组件把所有你的 CSS 加载到入口主文件中来做任何事情。
加载 CSS 需要 css-loader 和 style-loader,他们做两件不同的事情,css-loader会遍历 CSS 文件,然后找到 url() 表达式然后处理他们,style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。
安装加载器
在命令行中输入npm install css-loader style-loader --save-dev
安装完毕后可以将加载器配置到 Webpack.config.js 文件中。
webpack.config.js
var path = require('path');
var config = {
entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.jsx$/,
loader: 'jsx'
}, {
test: /\.css$/, // Only .css files
loader: 'style!css' // Run both loaders
}]
}
};
module.exports = config;
加载 CSS 文件
加载一个 CSS 文件就和加载其他文件一样:
main.js
import './main.css';
// Other code
Component.jsx
import './Component.css';
import React from 'react';
export default React.createClass({
render: function () {
return <h1>Hello world!</h1>
}
});
将所有CSS合并成一个
在你的主入口文件中个,比如 app/main.js 你可以为整个项目加载所有的 CSS:
app/main.js
import './project-styles.css';
// 其他 JS 代码
CSS 就完全包含在合并的应用中,再也不需要重新下载。
如果你想发挥应用中多重入口文件的优势,你可以在每个入口点包含各自的 CSS:
app/main.js
import './style.css';
// 其他 JS 代码
app/entryA/main.js
import './style.css';
// 其他 JS 代码
app/entryB/main.js
import './style.css';
// 其他 JS 代码
你把你的模块用文件夹分离,每个文件夹有各自的 CSS 和 JavaScript 文件。再次,当应用发布的时候,导入的 CSS 已经加载到每个入口文件中。
具体的组件
你可以根据这个策略为每个组件创建 CSS 文件,可以让组件名和 CSS 中的 class 使用一个命名空间,来避免一个组件中的一些 class 干扰到另外一些组件的 class
app/components/MyComponent.css
.MyComponent-wrapper {
background-color: #EEE;
}
app/components/MyComponent.jsx
import './MyComponent.css';
import React from 'react';
export default React.createClass({
render: function () {
return (
<div className="MyComponent-wrapper">
<h1>Hello world</h1>
</div>
)
}
});
使用内联样式取代 CSS 文件
在 “React Native” 中你不再需要使用任何 CSS 文件,你只需要使用 style 属性,可以把你的 CSS 定义成一个对象,那样就可以根据你的项目重新来考略你的 CSS 策略。
app/components/MyComponent.jsx
import React from 'react';
var style = {
backgroundColor: '#EEE'
};
export default React.createClass({
render: function () {
return (
<div style={style}>
<h1>Hello world</h1>
</div>
)
}
});