本文但願能幫助那些一直用腳手架而對工程化沒有概念的朋友。javascript
文中許多步驟會在運行時報錯,從錯誤中分析須要添加的配置,加深印象以及對所添加的每一行配置的理解。css
本文將以
React
爲例,帶你走一次。html
mkdir demo && cd demo
npm init
touch index.js
複製代碼
yarn add webpack webpack-cli --dev # 安裝webpack相關依賴
touch webpack.config.js # 新建webapck配置文件
複製代碼
這是一份最基本的webpack配置:前端
const path = require('path');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
複製代碼
在package.json中,添加scipts
以下:java
"scripts": {
"build": "webpack"
},
複製代碼
在命令行中執行node
npm run build
複製代碼
你會看到以下警告:react
WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: webpack.js.org/concepts/mo…webpack
因爲webpack
在4.0後,新增mode配置項,它爲咱們默認設置了production
。可是該警告並無影響build
的結果暫且忽略。 能夠看到dist
目錄已經生成了名爲my-first-webpack.bundle.js
文件。git
OK,最基本的配置已經完成,接下來引入React。程序員
yarn add react react-dom # 安裝react相關依賴
複製代碼
在使用前,須要在dist目錄中,添加index.html
,內容以下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React</title>
</head>
<body>
<div id="root"></div>
<script src="./my-first-webpack.bundle.js"></script>
</body>
</html>
複製代碼
從react官網官網找段HelloWorld貼過來吧,全英文看不懂?不要緊,代碼你總認識吧,貼就完了!
將index.js
中的內容變動以下:
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
複製代碼
OK,看似完美,執行下,build
看看效果。
ERROR in ./index.js 4:16
Module parse failed: Unexpected token (4:16)
You may need an appropriate loader to handle this file type.
| import ReactDOM from 'react-dom';
|
> ReactDOM.render(<div>Hello World</div>,
| document.getElementById('root'));
複製代碼
報錯了?莫慌,從錯誤信息中找關鍵字,You may need an appropriate loader to handle this file type.
。 這時候感慨一句,程序員是偉大的,錯誤信息很詳細了,告訴咱們須要適當的loader
來處理這個文件。什麼loader
?別問我,不是我乾的,繼續往下看剛纔的連接下一小節react-jsx的介紹,拉到最下面,是否是有一段關於官方的建議?繼續查找關鍵字,是否是看到一個叫Babel
的東西?納尼,莫非jsx
和它有關係?雖然這段話是說推薦編輯器設置的吧,可是程序員必備一顆好奇的心。
Google一下上面的關鍵詞Babel
,進去瞅瞅吧。 因而開始接觸一個新名詞Babel
,這玩意幹啥的?能爲咱們帶來什麼?看看首頁吧。
ES2015 及更高版本
Babel 經過語法轉換器支持最新版本的 JavaScript 。
Polyfill
因爲 Babel 只轉換語法(如箭頭函數), 你可使用 babel-polyfill 支持新的全局變量,例如 Promise 、新的原生方法。
JSX 和 Flow
Babel 可以轉換 JSX 語法並去除類型註釋。
可插拔
Babel 是創建在插件以外的。 你可使用已有的插件或者本身編寫插件來組成屬於你本身的轉換管道。
可調式
支持 Source map 所以能夠輕鬆調試編譯後代碼。
看完首頁的介紹,是否和我有一樣的感嘆:好東西啊!既然是好東西,用起來吧。 從配置的webpack
選項中,你會發現剛纔出現的兩個關鍵字都來了babel
、loader
,艾瑪,得來全不費工夫。
yarn add babel-loader babel-core babel-preset-env babel-polyfill babel-preset-react --dev
# 這波安裝比較長?由於咱們把剛纔看到的es201五、更高版本語法的,polyfill,jsx的都裝上了
複製代碼
config
配置將webpack.config.js
修改配置以下:
const path = require('path');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
};
複製代碼
.babelrc
配置文件touch .babelrc #建立.babelrc
複製代碼
將如下內容粘貼至.babelrc
中:
{
"presets": ["env", "react"]
}
複製代碼
至此,已經將上面的babel-preset-env
、babel-preset-react
使用上了,那polyfill
怎麼用呢?繼續看波文檔吧。emmm,寫的很清楚了,咱們把polyfill
使用上吧,修改webpack.config.js
中的配置以下:
const path = require('path');
module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
};
複製代碼
該配置的都配置完了,執行下npm run build
看看效果?果不其然,編譯過了。
你覺得工程就這樣配完了嗎?NO,這僅僅是個開始!
SPA工程中使用,什麼是SPA,單頁應用?什麼是單頁應用?只有一個html,公用js css僅引用一次,經過局部刷新渲染的應用。
react-router官網,按着快速上手的步驟來。
yarn add react-router-dom
複製代碼
Now you can copy/paste any of the examples into src/App.js. Here’s the basic one:
這裏從create-react-app
中使用方式,雖然咱們不是,可是咱們本身搭的也不差啊。本身建個src
和App.js
吧。
mkdir src && touch src/App.js
複製代碼
將官方的🌰貼進來App.js
:
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const Home = () => (
<div> <h2>Home</h2> </div>
)
const About = () => (
<div> <h2>About</h2> </div>
)
const Topic = ({ match }) => (
<div> <h3>{match.params.topicId}</h3> </div>
)
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
Components
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Route path={`${match.path}/:topicId`} component={Topic}/>
<Route exact path={match.path} render={() => (
<h3>Please select a topic.</h3>
)}/>
</div>
)
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
export default BasicExample
複製代碼
接下來在index.js
中引用:
import React from 'react'
import ReactDOM from 'react-dom';
import App from './src/App';
ReactDOM.render(
<App />, document.getElementById('root') ); 複製代碼
執行npm run build
看看。沒報錯,使用瀏覽器打開dist/index.html
看看。點擊連接沒反應?什麼狀況?莫慌,打開控制檯看看:
Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///' cannot be created in a document with origin 'null' and URL
emmmm,咋整?別問我,真不是我乾的… 既然chrome很差使,就再看一眼safari下好很差用吧,同樣很差使,再看一眼報錯信息。
[Error] SecurityError: Blocked attempt to use history.pushState() to change session history URL from file:///demo/dist/index.html to file:///about. Paths and fragments must match for a sandboxed document.
好像safari的報錯更友好一些,咱們能夠清楚的看到,它在試圖改變連接,爲了安全起見,你認爲這麼作合理麼?豈不是拿個html能訪問計算機任何文件了?emmm,果真不合理。再看關鍵詞: Paths and fragments must match for a sandboxed document
。
那咱們就構建個沙盒環境吧。
yarn add webpack-dev-server --dev
複製代碼
在package.json
中添加scripts
:
"dev": "webpack-dev-server"
複製代碼
在webpack.config.js
根節點中,添加:
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
複製代碼
執行上面剛添加的srcripts
:
npm run dev
複製代碼
瀏覽器中打開連接localhost:9000
功能沒問題,樣式無法忍,有木有?改!
在src
中新建app.css
文件,新增以下內容:
.container {
list-style: none;
}
複製代碼
在App.js
中,添加以下代碼:
import './app.css';
複製代碼
將BasicExample
中的ul
應用樣式:
<ul className="container">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
複製代碼
這時,你會發現一個熟悉的錯誤。
You may need an appropriate loader to handle this file type.
此次咱們能夠很快的定位到,缺乏加載css
相關的loader
。
loader
相遇webpack相關文檔 雖然,webpack
的文檔老是那麼的不及時,可是一些基礎性的東西,仍是能從中學到的。既然又一次遇到了loader
,不妨此次咱們就完全搞明白什麼是loader
,它爲咱們提供了什麼?
loader 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件。所以,loader 相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!
看完這麼長一段,我總結了一句話,經過import
來處理的文件,須要對應的loader。既然如此,那就一個一個安吧。
css-loader
yarn add style-loader css-loader --dev
複製代碼
修改webpack.config.js
中,module
下的rules
,就像添加babel-loader
同樣,添加以下配置:
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
複製代碼
關於css-loader這裏要再多提一句,當你不想對全局css進行污染,想經過如下方式使用時:
import styles from 'app.css';
<div className={styles.container} /> 複製代碼
請使用css module,webpack配置css module的方式也十分簡單:
'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
複製代碼
將 css-loader
調整成以上內容便可。
file-loader
處理各類圖標、圖片文件
yarn add file-loader --dev
複製代碼
修改webpack.config.js
中,module
下的rules
,添加以下配置:
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
複製代碼
字體文件依舊由file-loader
處理,繼續添加配置:
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
複製代碼
loader
暫時添加到這裏,這時記住了沒?想讓webpack
處理對應文件,就要有對應的loader
。
繼續刷新看咱們的demo工程,生效了。
loader
配置完,繼續按着文檔來吧,看看咱們還有什麼能夠了解的。
插件是 webpack 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上!
插件目的在於解決 loader 沒法實現的其餘事。
管理輸出中有這麼一段:
若是咱們更改了咱們的一個入口起點的名稱,甚至添加了一個新的名稱,會發生什麼?生成的包將被重命名在一個構建中,可是咱們的index.html文件仍然會引用舊的名字。咱們用 HtmlWebpackPlugin 來解決這個問題。
OK,瞭解了它的目的,有用,裝!
yarn add html-webpack-plugin --dev
複製代碼
在webpack.config.js
的根節點中添加plugins
:
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
複製代碼
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
複製代碼
重啓下npm run dev
,你會發現頁面空白了?臥槽,這不是坑麼?打開控制檯看一眼,Target container is not a DOM element.
,再看一眼Elements
選項卡中的內容,發現,咦。好像咱們的<div id="root"></div>
神奇的消失了。 再看文檔,發現這麼一句話:
若是你想要了解更多 HtmlWebpackPlugin 插件提供的所有功能和選項,那麼你就應該多多熟悉 HtmlWebpackPlugin 倉庫。 其中的配置項中,
template
這項是這麼描述的: webpack require path to the template. Please see the docs for details
模板啊,咱們把dist/index.html
中的文件挪出來,放到項目的根目錄下,而後再修改下webpack.config.js
中的配置:
new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
})
複製代碼
重啓下服務看看吧,npm run dev
頁面出來了,可是報了個錯:only one instance of babel-polyfill is allowed
。 這又是什麼錯?咱們明明只有一個entry
,爲何說引了屢次呢?打開Elements
選項卡中,驚奇的發現,原來是咱們剛纔直接從dist
目錄中挪的index.html
中,還存在<script src="./my-first-webpack.bundle.js"></script>
這麼一段script
,刪掉,再重啓。大功告成。
你可能已經注意到,因爲過去的指南和代碼示例遺留下來,致使咱們的 /dist 文件夾至關雜亂。webpack 會生成文件,而後將這些文件放置在 /dist 文件夾中,可是 webpack 沒法追蹤到哪些文件是實際在項目中用到的。
依然有用,依然裝!
yarn add clean-webpack-plugin --dev
複製代碼
修改webpack.config.js
: 引入CleanWebpackPlugin
:
const CleanWebpackPlugin = require('clean-webpack-plugin');
複製代碼
添加plugins
:
new CleanWebpackPlugin(['dist']),
複製代碼
爲何要區分生產環境與開發環境?
開發環境(development)和生產環境(production)的構建目標差別很大。在開發環境中,咱們須要具備強大的、具備實時從新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,咱們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。因爲要遵循邏輯分離,咱們一般建議爲每一個環境編寫彼此獨立的 webpack 配置。
按照官方教程,來進行拆分。在此,我更推薦新建config
目錄,將配置統一放置config
中,因此此時咱們的配置文件應該是:
config/webpack.common.js
:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[contenthash:12].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /\.css$/,
use: [
'style-loader',
"css-loader"
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(["dist"], {
root: path.resolve(__dirname, "../"),
}),
new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
})
]
};
複製代碼
config/webpack.dev.js
:
const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
compress: true,
port: 9000
}
});
複製代碼
config/webpack.prod.js
:
const merge = require('webpack-merge');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'production',
});
複製代碼
另外,package.json
中的scripts
也要進行相應的調整:
"build": "webpack --config config/webpack.prod.js",
"dev": "webpack-dev-server --config config/webpack.dev.js"
複製代碼
tips: 這是一個從入門到放棄的Plugin,感興趣的話能夠繼續跟着操做,沒興趣請跳至下個小節。
它會將全部的入口 chunk(entry chunks)中引用的 *.css,移動到獨立分離的 CSS 文件。
yarn add extract-text-webpack-plugin --dev
複製代碼
照着文檔中的🌰把配置貼進來,修爲webpack.config.js
:
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
mode: "production",
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
],
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
};
複製代碼
重啓服務的時候,你會發現報錯了?WTF?費了半天勁,結果還不能用?這時候咱們須要注意一點,就是它曾經確定是能用的,否則不能放到文檔上,這就體現出來webpack
文檔落後了。既然如此,由於咱們當下使用的是webpack 4.x
的版本,這時候先去ExtractTextWebpackPlugin的github上搜搜有沒有想過issue吧,關鍵詞webpack 4
。 看到一個issue。
@vasivas don't use extract-text-webpack-plugin for extract css, please use github.com/webpack-con…
居然還有這種操做,那就看看這個mini-css-extract-plugin
。
關於webpack,就引導到這裏,本文不是對webpack進行講解,更多關於webpack
的部分,能夠看: @花褲衩 寫的文章:
最終咱們關於分離css的內容變成以下: webpack.common.js
:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: ["babel-polyfill", "./index.js"],
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[contenthash:12].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader?cacheDirectory"
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(["dist"], {
root: path.resolve(__dirname, "../"),
}),
new HtmlWebpackPlugin({
title: 'Demo',
template: './index.html'
}),
]
};
複製代碼
webpack.prod.js
:
const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = merge(common, {
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({}) // use OptimizeCSSAssetsPlugin
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:12].css',
chunkFilename: '[name].[contenthash:12].css' // use contenthash *
})
]
});
複製代碼
webpack.dev.js
:
const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
compress: true,
port: 9000
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
]
});
複製代碼
依舊看上面 @花褲衩 的文章,分的很細膩。在此咱們簡單分離:
在webpack.common.js
中修改:
const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = merge(common, {
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({}) // use OptimizeCSSAssetsPlugin
],
runtimeChunk: {
name: "manifest"
},
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -20,
chunks: "all"
}
}
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:12].css',
chunkFilename: '[name].[contenthash:12].css' // use contenthash *
})
]
});
複製代碼
OK,看似完美。
React
、Babel
、webpack
都有了,接下來就是爲了本身與團隊之間協做代碼的規範性,要經過下一個工具了。
npm install eslint -g #全局安裝eslint
複製代碼
eslint --init
複製代碼
? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
? The style guide "airbnb" requires eslint@^4.19.1. You are currently using eslint@5.2.0.
Do you want to downgrade? Yes
複製代碼
在此直接選擇airbnb
。
在初次安裝後,咱們發現咱們以前的App.js
報錯了,這時咱們須要調整eslint
相關的配置規則,來讓它更符合咱們預期的使用: 打開.eslintrc.js
文件,調整內容以下:
module.exports = {
"extends": "airbnb",
"plugins":[
"react",
"jsx-a11y",
"import"
],
"rules": {
"import/no-extraneous-dependencies": "off",
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"react/prop-types": 0
}
};
複製代碼
更多eslint
的使用姿式,還須要你我的進行探索。
ant-design
yarn add antd
複製代碼
若不想每次引用css時,可選用,在這裏使用babel-plugin-import
:
yarn add babel-plugin-import --dev
複製代碼
修改.babelrc
文件中修改成:
{
"presets": ["env", "react"],
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}
複製代碼
在App.js
中,進行引用:
import { DatePicker } from 'antd';
const Home = () => (
<div> <h2> <DatePicker /> </h2> </div>
);
複製代碼
刷新後咱們發現,組件是顯示出來了,可是樣式並無生效。繼續去找解決方案: www.jianshu.com/p/603a61471… 這位老哥寫的很清楚了,原來是咱們的rules
配置還有點瑕疵,根據內容調整以下:
{
test: /\.css$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
],
},
{// antd樣式處理
test: /\.css$/,
exclude: /src/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
],
},
複製代碼
調整完後,重啓webpack
。
本文只作引子,讓你對前端工程化有必定的瞭解,更多的還需本身去根據關鍵字探索。
本人上上週搞得的基於百度地圖的封裝現已開源,歡迎加入一塊兒搞事情: