工欲善其事,必先利其器。单页面运用的开辟和临盆环境触及文件的编译、紧缩、打包、兼并等,如今前端最盛行的莫过于 webpack
。为了深切相识 webpack
以及其相干插件,我们决议不采纳脚手架,本身来搭建基于 webpack
的开辟和临盆环境。
基本环境
nodejs的装置: 移步官网
发起运用nvm来治理nodejs的版本
装置nvm
Webpack相干plugin、loader的引见
我们运用的是 webpack@2.X.X
,发起读完 官方文档 对她有个也许的相识。
webpack-dev-server 用
webpack-dev-server
来举行开辟环境下面的自动打包编译,包含热更新等等。固然也能够本身经由过程webpack-dev-middleware
来自定义一个开辟服务器。细致能够参考webpack-dev-server
的源代码。webpack-hot-middleware 向进口文件中增添一个
client
文件,当文件变化时,服务器端能够经由过程socket
事宜来关照这个client
来完成热更新。注:这个事宜是 EventSource事宜。webpack-dev-server
已将这个中间件封装到内部,我们只须要举行设置即可。babel-loader 编译
es6
代码。移步官网。值得一提的是es2016
,es2017
,env
等是对已或许将要被到场 JS这门言语的提案举行预编译,而stage-0
,stage-1
,stage-2
等是对未来能够到场备案内里的语法的预编译。extract-text-webpack-plugin 款式文件默许会被 webpack 打包到js文件中。这个插件能够提掏出这些被打包进入的文件。
固然我们用到的不只是这些,你能够到npm官网或许github上面找到这些plugin、loader的细致用法
初始目次构造
blog
├─ dist # 输出目次
├─ task # 这里来放webpack处置惩罚和设置文件
├─ src
| ├─ components # 组件
| └ index.js # 进口文件
| package.json
跑通开辟环境
在 src/
目次下新建进口文件 index.js
import React from 'react'
import ReactDOM from 'react-dom'
// 这里须要借助 webpack 的同名功能来替代烦琐的相对途径
import HomeComponent from 'components/Home'
ReactDOM.render(<HomeComponent />, document.getElementById('root'))
在 src/component/
目次下新建 Home.js
模块
import React, { Component } from 'react'
export default class Home extends Component {
render(){
return <div>Hello world!</div>
}
}
在 src/
目次下新建 index.html
文件来作为单页面的HTML文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>blog</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
如今我们来增添 webpack
的设置文件来对这些文件举行打包、编译
在 task/
目次下新建 config.js
文件
const path = require('path')
const webpack = require('webpack')
const webpackMerge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const base = {
// 上下文环境,相对途径都基于这个途径
context: path.resolve(__dirname, '..'),
entry: './src/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/assets/',
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, '../src'),
exclude: [ /node_modules/ ],
use: [
'react-hot-loader',
{
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
plugins: [
"add-module-exports",
"transform-runtime"
]
}
}
],
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
// 这里对应着进口文件中 component 的同名设置
components: path.resolve(__dirname, '../src/components')
}
}
}
const dev = webpackMerge(base, {
output: {
publicPath: '/'
},
// 源文件的 source map
devtool: "source-map",
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: true
})
],
devServer: {
// 开启热加载,须要 hmr 的支撑
hot: true,
contentBase: path.resolve(__dirname, '../dist'),
// 这个途径肯定要和 output 的 publicPath 的属性一致
publicPath: '/',
}
})
const prod = webpackMerge(base, {
})
// 依据 NODE_ENV 来决议输出的设置
module.exports = process.env.NODE_ENV === 'production' ? prod : dev
在项目跟途径下实行
export NODE_ENV=development && webpack-dev-server --config ./task/config.js
export NODE_ENV=development
设置 NODE_ENV
这个环境变量为 development
有助于我们辨别开辟环境和临盆环境。这是mac下面的设置要领,windows 能够自行搜刮
编译胜利,而且页面输出 Hello world!
示意设置跑通…
在 package.json
增添
{
"scripts": {
"dev": "export NODE_ENV=development && webpack-dev-server --config ./task/config.js --progress --colors --hotOnly"
}
}
TROUBLESHOOTING
经由过程 webpack-merge
来掩盖 output.publicPath
属性
假如 devServer.publicPath = output.publicPath = '/assets/'
的话,那末在浏览器中翻开 localhost:80XX/assets/index.html
才接见到 index.html
文件,而将 publicPath = '/'
就直接经由过程 localhost:80XX
就能够接见。
loader
的设置
个中 include
, exclude
就不多说
{
use: [
'react-hot-loader',
{
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
plugins: [
"add-module-exports",
"transform-runtime"
]
}
}
],
}
react-hot-loader 会处理变动 react 组件的时 webpack 热更新直接革新页面的题目。
babel-presets-react
用来处置惩罚 react 的 jsx 语法
babel-plugin-add-module-exports babel@6
会将es6的语法
// home.js
export default 'foo'
转化为
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = 'foo';
所以在运用 commonjs
的语法 require('./home')
时,获得的是{default: 'foo'}
,所以:
var home = require('./home').default
console.log(home) // 'foo'
这个插件能够防止这一征象
html-webpack-plugin
这里解释一下运用 html-webpack-plugin
的必要性。
实在完全能够扔一个静态的 index.html
给 webpack-dev-server
,这内里只须要有个 <script src="bundle.js"></script>
标签,就能够胜利来举行接见。然则更多的时刻我们会定制打包文件的称号: output.filename: '[name]-[hash].js'
,编译以后 webpack
会输出一个类似于如许的文件 bundle-fb9758acf17b2b5fb653.js
,那末你每次打包都须要去变动谁人src属性,而 html-webpack-plugin
能够帮你处理这些事变
增添对款式文件的支撑
在 src/component/
下新建 Home.module.less
@color: green;
:global {
body {
background-color: red;
}
}
.wrap {
color: @color;
}
在同级目次下的 Home.js
组件中引入这个 less 文件
import React, { Component } from 'react'
import Style from './home.module.less'
export default class Home extends Component {
render(){
return <div className={Style.wrap}>Hello world!</div>
}
}
我们没有在 task/config.js
下增添对 less
文件的支撑,肯定会报错的。先说一下为何要以 .module.less
标识 less
文件,只会我们会引入 babel-plugin-import
对款式库 antd
举行按需加载,因为 antd
源代码中的款式文件也是用 less
写的,如许会致使这些文件被作为 css-module
处置惩罚,所以加以区分,这是参考 atool-build 的设置。
在 task/config.js
文件新增 :
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const autoprefixer = require('autoprefixer')
const runsack = require('rucksack-css')
const theme = require('../theme.js')()
const postcssPlugins = () => [
runsack(), // 可选
autoprefixer({
browsers: ['last 2 versions', 'Firefox ESR', '> 1%', 'ie >= 8', 'iOS >= 8', 'Android >= 4'],
}),
]
// 在base.module.rules里增添
{
test: /\.module\.less$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader', // 将下面处置惩罚过的文件插进去html中
use: [
{
loader: 'css-loader',
// 开启对css-module的支撑,并定义className的输出花样
options: { modules: true, importLoaders: 1, localIdentName: '[name]__[local]___[hash:base64:5]'}
},
{
loader: 'postcss-loader',
options: {
plugins: postcssPlugins
}
},
{
loader: 'less-loader',
// 掩盖默许的全局设置
options: {"modifyVars": theme}
}
]
})
},
// 在 base.plugins 里增添
new ExtractTextPlugin({
filename: 'css/[name]-[hash].css',
}),
其他的 loader 和 webpack plugin 就不再赘述, 移步文档
还要注重的是
less-loader
中的设置选项,{"modifyVars": theme}
,这能够掩盖less
文件的设置,能够用来自定义款式库antd
, 继承检察
在项目根目次下新建 theme.js
module.exports = function(){
return {}
}
别忘记装置设置文件内里用到的 loader、pulgins… = =
装置 less-loader
记得把 less
也装上,它的文档也是有强调的哦!
小结
基本的环境设置就到这里。临盆环境你能够自行设置,以后我会在后面的文章中列出来。
你能够在这个堆栈检察 这第一次 commit 哦!下面皆能够兴奋的做本身的博客了!