刚接触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')],};
按上述目录时,__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('',output: { path: path.resolve(__dirname,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',resolve: { alias: { 'react': pathToReact } },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',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> ) } });