搭建一個AngularJs+TypeScript項目

因為需要做一個webpack+angularjs+typescript的項目,angularjs(以下都稱為angular)之前看過一點,那么首先遇到的問題就是我們怎么使用webpack來搭建一個angular的開發(fā)環(huán)境。

因為不是很了解typescript,所以打算先用js做

起步

首先我們根據(jù)webpack官網(wǎng)的起步來初步認(rèn)識一下webpack的配置和使用。

簡單了解了一下之后,我遇到兩個問題:

  1. 怎么引入angular依賴
  2. 怎么引入bootstrap這種全局依賴

過去使用yeoman來搭建angular開發(fā)環(huán)境時,使用的是bower下載安裝依賴,并使用grunt/gulp將js和css文件注入到html當(dāng)中

這時angular被作為全局依賴加入到全局作用域,我們可以在任意文件中調(diào)用angular這個全局對象

而在使用webpack的項目中,我們可以看到所有的依賴都是通過import/require加載進來,這讓剛接觸的我感到十分困惑

之后參考了一些其他項目,找到了解決辦法

引入angular

實際上引入angular很容易,只需要在用到的地方import一下就可以了

import angular from 'angular'

打包第三方依賴

對于bootstrap這種全局依賴項,我希望能夠單獨打包成一個js文件,與我們的開發(fā)文件分離開來

有一種解決方案是,單獨再創(chuàng)建一個入口文件,在這里導(dǎo)入我們需要的全局依賴,然后單獨output一個打包后的依賴庫文件

externals文件

import 'angular';
import 'angular-ui-router';
import 'angular-aria';
import 'angular-animate';
import 'angular-messages';
import 'angular-material';

export default ['ui.router','ngMaterial'];

webpack配置文件

module.export = {
    entry: {
        externals: resolve(__dirname, 'app', 'externals', 'index.js'),
        app: resolve(__dirname, 'app', 'index.js')
    },
    output: {
        path: resolve(__dirname, 'build'),
        filename: '[name].bundle.js',
        publicPath: '/'
    }
}

導(dǎo)入angular-module

有時我們需要在聲明module時導(dǎo)入依賴

這個時候我們再在我們的入口文件中導(dǎo)入我們剛才導(dǎo)出的數(shù)組就好啦

import Dependence from './externals';

const app = angular.module('myApp', Dependence);

可以試一試material組件,發(fā)現(xiàn)已經(jīng)可以使用了

這里不會導(dǎo)入material的css文件,需要自己導(dǎo)入,后面會講怎么操作,可以先用cdn

引入CSS文件

注意:很多配置文件都會這么寫

module.export = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    { loader: 'style-loader' },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    }
                ]
            }
        ]
    },
}

當(dāng)你導(dǎo)入自己的css文件時會發(fā)現(xiàn)你的類名變成了很奇怪的樣子

div{
    width: 80%;
    margin: auto;
}
.vZRtpaKB-zShEJMBqrZ7B{
    color: red;
}

這里其實是使用了css module如果你不需要使用css module,或者說你是一個像我一樣的小白,可以先把options去掉,這樣導(dǎo)入的css文件就和我們以前用的一樣了

了解css module

module.export = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            }
        ]
    },
}

導(dǎo)入庫文件的css

前面提到我們在導(dǎo)入material的時候是不會導(dǎo)入他的css文件的,如果你直接在html中l(wèi)ink node_module中的文件,那么在你使用打包后的文件時,會報一個MIME type的錯誤,實際上這是對服務(wù)器靜態(tài)資源訪問的限制。我們需要設(shè)置一個靜態(tài)資源文件夾,來存放網(wǎng)頁中使用到的靜態(tài)文件(如css)

報MIME type錯誤,實際上是對服務(wù)器靜態(tài)資源訪問的限制這個說法不一定正確

這里我們要用到一個插件,幫我們把css文件復(fù)制到打包目錄下

plugins:[
    new CopyWebpackPlugin([
        { from:'node_modules/angular-material/angular-material.min.css',to:'assets'},
    { from:'node_modules/bootstrap/dist/css/bootstrap.min.css',to:'assets'}
    ])
]

之后我們就可以在html文件中引用同目錄assets文件夾中的css文件了

優(yōu)化

刪除相同引用

我們可能會在很多文件中引入相同的依賴,比如jQuery

這時,webpack會打包多份jQuery庫到我們的bundle文件當(dāng)中,這不是我們希望發(fā)生的

版本問題

webpack.optimize.CommonsChunkPlugin已經(jīng)不再被支持,需要替換為config.optimization.splitChunks

于是我們現(xiàn)在要使用config.optimization.splitChunks來解決這個問題

optimization: {
    splitChunks: {
        cacheGroups: {
            commons: {
                test: /[\\/]node_modules[\\/]/,
                name: "externals",
                chunks: "all"
            }
        }
    }
},

打包之后我們會發(fā)現(xiàn)現(xiàn)在的app.bundle.js文件只有12KB大小,說明已經(jīng)不再包含angular庫文件了??刂婆_也不會再有WARNING: Tried to load AngularJS more than once.的提示了。

壓縮文件

當(dāng)一個項目上線發(fā)布時,我們還需要考慮到文件的大小。目前我們的externals文件還有3.5MB大小,加載起來比較困難。

調(diào)整配置

這時我們就不應(yīng)該使用mode:'development'了,將其切換成mode:'production',同時也可以考慮關(guān)掉source-map

這時再打包,我們發(fā)現(xiàn)app.bundle.js文件已經(jīng)只有2KB了,而externals.bundle.js文件也縮小為731KB

壓縮時出現(xiàn)的問題

這時我們起一個服務(wù)器看看打包出來的文件,會發(fā)現(xiàn)報了一個錯誤
[$injector:unpr] Unknown provider: tProvider <- t <- MainCtrl

這是由于壓縮時簡寫了參數(shù)名引起的,看下面這個例子

app.controller('MainCtrl', function ($scope, $mdDialog){
    ...
}
// 壓縮之后
.controller("MainCtrl",function(t,e){this.hello="hello",t.showAlert=function(t){e.show(e.alert().parent(o.a.element(document.querySelector("#root"))).clickOutsideToClose(!0).title("This 

我們可以看到原本的scope和mdDialog被替換成了t和e,而angular無法識別這里的t和e,所以出現(xiàn)了錯誤

正確的寫法是這樣

app.controller('MainCtrl', ['$scope', '$mdDialog', function ($scope, $mdDialog){
    ...
}

這樣前面的$scope, $mdDialog和后面?zhèn)魅氲膮?shù)已經(jīng)對應(yīng)起來,就不會無法識別啦

也就是說,無論后面?zhèn)魅氲氖鞘裁疵?,都會和前面?shù)組中的參數(shù)一一對應(yīng)

參考

webpack文檔

generator-ts-angular

material-start

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容