接下來就要進行工程化的操作了,主要有兩個目的。
- 對靜態文件進行編譯、打包、壓縮、版本控制等優化操作;
- 構建一個便利的開發環境,比如熱加載、代理等。
這裏我們會用到webpack,輔以babel以及其他loader來處理js、css、圖片等靜態文件。對於各種loader的作用,本文會有一個大概的介紹,但不會展開說明,推薦看webpack文檔來做一個詳細的瞭解。
1、安裝webpack及各種loader和plugin
$ npm i -D webpack@3 webpack-dev-server@2 webpack-merge babel-core babel-loader babel-preset-env babel-preset-stage-2 css-loader style-loader less less-loader postcss-loader postcss-import postcss-url url-loader file-loader extract-text-webpack-plugin html-webpack-plugin
(注:截止至筆者寫作日,webpack4還不穩定,所以還是用webpack3,相應的需要webpack-dev-server@2)
說明:
- babel-core、babel-loader、babel-preset-env、babel-preset-stage-2,babel相關負責將js編譯爲es5規範,要新增.babelrc配置文件。
- css-loader、style-loader,負責css的編譯,webpack文檔裏可以找到。
- postcss-loader、postcss-import、postcss-url,postcss負責給樣式添加瀏覽器前綴的兼容(如-webkit-),要新增.postcssrc.js配置文件。
- less、less-loader樣式預編譯,當然也可以用sass。
- url-loader,負責img、font等靜態文件編譯。
- extract-text-webpack-plugin,負責將css提取爲單獨的文件。
- html-webpack-plugin,負責向html模板中動態寫入靜態文件引用。
2、修改代碼
src/index.css重命名爲src/index.less
src/index.js(所有資源都用import引入,並把方法提取到util.js文件,方便後面的內容)
import { strReverse } from '@util';
import './index.less';
import logo from './assets/logo.jpg';
const $app = document.getElementById('app');
const strInput = 'Hello World';
const srtHolder = 'The result will be here...';
const strHtml = `
<img src="${logo}" alt="logo" />
<h1>${strInput}</h1>
<button id="do">Show the reverse of "${strInput}"</button>
<button id="reset">Do reset</button>
<p id="result">${srtHolder}</p>
`;
$app.innerHTML = strHtml;
const $result = document.getElementById('result');
document.getElementById('do').onclick = () => {
$result.innerHTML = `The reverse of "${strInput}" is "${strReverse(strInput)}"`;
};
document.getElementById('reset').onclick = () => {
$result.innerHTML = srtHolder;
};uti
新建src/util/index.js
export function strReverse(str) {
return str.split('').reverse().join('');
}
index.html(去掉引用,webpack會自動加入)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello World</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
3、配置webpack、babel、postcss
webpack默認的配置文件是webpack.config.js。但是通常的,我們會在開發環境引用webpack.dev.js,生產環境用webpack.prod.js,所以我們一步到位,建立config目錄,直接寫webpack.prod.js,webpack.dev.js並且用webpack-merge提取出它們的公共部分webpack.base.js,方便管理。這裏我們把jsx的坑先給填了,反正不影響。
config/webpack.base.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const root = path.resolve(__dirname, '../');
module.exports = {
entry: path.resolve(root, 'src'),
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'Hello World',
template: './index.html',
}),
],
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'src': path.resolve(root, 'src'),
'util': path.resolve(root, 'src/util'),
},
},
};
config/webpack.dev.js
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./webpack.base');
const root = path.resolve(__dirname, '../');
module.exports = webpackMerge(baseConfig, {
output: {
path: path.resolve(root, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(css|less)$/,
include: path.resolve(root, 'src'),
use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
},
],
},
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.resolve(root, 'dist'),
port: 9000,
hot: true,
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
});
config/webpack.prod.js
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./webpack.base');
const root = path.resolve(__dirname, '../');
module.exports = webpackMerge(baseConfig, {
output: {
path: path.resolve(root, 'dist'),
filename: 'bundle.[chunkhash:10].js',
},
module: {
rules: [
{
test: /\.(css|less)$/,
include: path.resolve(root, 'src'),
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader',
options: {
minimize: true,
},
}, 'postcss-loader', 'less-loader'],
}),
},
],
},
devtool: '#source-map',
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
},
},
sourceMap: true,
parallel: true,
}),
new ExtractTextPlugin({
filename: 'bundle.[contenthash:10].css',
allChunks: true,
}),
],
});
.babelrc
{
"presets": [
["env",{ "modules": false }],
"stage-2"
]
}
.postcssrc.js
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
"autoprefixer": {}
}
}
然後,在package.json裏的scripts里加上prod和dev,分別對應生產和開發環境
"scripts": {
"prod": "webpack --config config/webpack.prod.js",
"dev": "webpack-dev-server --config config/webpack.dev.js --open"
},
4、試運行
先試試生產環境的命令,在命令行裏輸入
$ npm run prod
可以看到,生成了一個dist文件夾,這個就是我們以後會放到生產環境的文件夾。但是!!我們之前已經把它gitignore了。這樣做的目的是爲了不污染線上的環境,每次上線都是在線上打包,不會出現開發時的各種開發到一半的文件。
從今以後,我們想要看效果,就要點開dist/index.html文件來看了。打開試試吧。
再試試開發環境的命令
$ npm run dev
瀏覽器打開localhost:9000或127.0.0.1:9000。隨便改一改js或css試試,是不是自動刷新了。這在我們開發時會比較有好一些,現在整體的環境已經有一個完整的雛形了。別忘了提交git,記錄一下
$ git add .
$ git commit -m 'webpack init'
5、配置展示
全部變化可看筆者的github記錄,還是很清晰的。
package.json
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"prod": "webpack --config config/webpack.prod.js",
"dev": "webpack-dev-server --config config/webpack.dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.1.0",
"postcss-import": "^11.1.0",
"postcss-loader": "^2.1.3",
"postcss-url": "^7.3.1",
"style-loader": "^0.20.3",
"url-loader": "^1.0.1",
"webpack": "^3.11.0",
"webpack-dev-server": "^2.11.2",
"webpack-merge": "^4.1.2"
}
}
項目結構
demo
|- config
|- webpack.base.js
|- webpack.dev.js
|- webpack.prod.js
|- src/
|- assets/
|- logo.jpg
|- index.css
|- index.js
|- .babelrc
|- .gitignore
|- .postcssrc.js
|- index.html
|- package.json