วิธีรวมสคริปต์ที่อยู่ภายในโฟลเดอร์ node_modules


275

ฉันมีคำถามเกี่ยวกับวิธีปฏิบัติที่ดีที่สุดในการรวมnode_modulesไว้ในเว็บไซต์ HTML

ลองนึกภาพฉันมี Bootstrap อยู่ในnode_modulesโฟลเดอร์ ตอนนี้สำหรับเว็บไซต์เวอร์ชันการผลิตฉันจะรวมสคริปต์ Bootstrap และไฟล์ CSS ที่อยู่ในnode_modulesโฟลเดอร์ได้อย่างไร มันเหมาะสมไหมที่จะปล่อย Bootstrap ไว้ในโฟลเดอร์นั้นและทำสิ่งต่อไปนี้?

<script src="./node_modules/bootstrap/dist/bootstrap.min.js"></script>

หรือฉันจะต้องเพิ่มกฎในไฟล์อึกของฉันซึ่งคัดลอกไฟล์เหล่านั้นไปยังโฟลเดอร์ dist ของฉันหรือไม่ หรือมันจะเป็นการดีที่สุดถ้าให้อึกเอา bootstrap ในเครื่องออกจากไฟล์ HTML ของฉันและแทนที่ด้วย CDN เวอร์ชั่น?


2
หัวข้อที่เกี่ยวข้องstackoverflow.com/questions/24397379/... ดังนั้นนี่คือเควสติโน @Palak Bhansali สมมติว่าเราต้องการเพียงอย่างเดียวหรือไม่มันแสดงให้เห็นถึงการใช้ bower เพื่อจุดประสงค์นี้เพียงอย่างเดียวตัวอย่างเช่น gulp express app isntalling bootstrap โดยตรงจาก npm ต้องการเข้าถึงไฟล์ใน gulp ซึ่งอยู่ใน node_modules สิ่งนี้แสดงให้เห็นถึงกรณีการใช้งานเพียงครั้งเดียวเพื่อต้องการความร่มรื่นในตอนนี้เพื่อจุดประสงค์เดียวหรือไม่? นั่นคือปัญหาที่ฉันพบเจอ ฉันใช้นักแต่งเพลง, npm, gulp, grunt, ไม่ต้องการ bower เป็นการส่วนตัวและไม่ต้องการ grunt ในแอพนี้เช่นกัน
blamb

คำถามที่ยอดเยี่ยมที่ต้องการโซลูชันที่ใช้งานง่าย!
Sydwell

คำตอบ:


297

โดยปกติแล้วคุณไม่ต้องการเปิดเผยเส้นทางภายในของคุณสำหรับวิธีที่โครงสร้างเซิร์ฟเวอร์ของคุณไปสู่โลกภายนอก สิ่งที่คุณสามารถทำได้คือทำให้/scriptsเส้นทางแบบคงที่ในเซิร์ฟเวอร์ของคุณที่จะดึงไฟล์จากสิ่งที่พวกเขาเกิดขึ้นไดเรกทอรีจะอาศัยอยู่ใน. "./node_modules/bootstrap/dist/"ดังนั้นถ้าไฟล์ของคุณอยู่ใน จากนั้นแท็กสคริปต์ในหน้าเว็บของคุณจะมีลักษณะดังนี้:

<script src="/scripts/bootstrap.min.js"></script>

หากคุณกำลังใช้ express กับ nodejs เส้นทางแบบสแตติกจะง่ายอย่างนี้:

app.use('/scripts', express.static(__dirname + '/node_modules/bootstrap/dist/'));

จากนั้นการร้องขอใด ๆ จากเบราว์เซอร์/scripts/xxx.jsจะต้องไปดึงมาโดยอัตโนมัติจากคุณไดเรกทอรีที่dist__dirname + /node_modules/bootstrap/dist/xxx.js

หมายเหตุ: รุ่นที่ใหม่กว่าของ NPM วางสิ่งต่าง ๆ ไว้ที่ระดับบนสุดไม่ซ้อนกันดังนั้นถ้าคุณใช้ NPM รุ่นที่ใหม่กว่าชื่อเส้นทางจะแตกต่างจากที่ระบุไว้ในคำถามของ OP และในคำตอบปัจจุบัน แต่แนวคิดยังคงเหมือนเดิม คุณหาที่ไฟล์จะถูกร่างกายอยู่ในไดรฟ์เซิร์ฟเวอร์ของคุณและให้คุณapp.use()กับการexpress.static()ที่จะทำให้การหลอกเส้นทางไปยังไฟล์เหล่านั้นเพื่อให้คุณไม่เปิดเผยไฟล์เซิร์ฟเวอร์องค์กรระบบที่เกิดขึ้นจริงให้กับลูกค้า


หากคุณไม่ต้องการสร้างเส้นทางแบบคงที่เช่นนี้คุณน่าจะดีกว่าเพียงแค่คัดลอกสคริปต์สาธารณะไปยังเส้นทางที่เว็บเซิร์ฟเวอร์ของคุณปฏิบัติต่อ/scriptsหรือกำหนดระดับสูงสุดที่คุณต้องการใช้ โดยปกติคุณสามารถทำให้ส่วนนี้เป็นส่วนหนึ่งของกระบวนการสร้าง / ปรับใช้ของคุณ


หากคุณต้องการให้ไฟล์หนึ่งไฟล์เป็นไฟล์สาธารณะในไดเรกทอรีและไม่ใช่ทุกสิ่งที่พบในไดเรกทอรีนั้นคุณสามารถสร้างเส้นทางแต่ละเส้นทางด้วยตนเองสำหรับแต่ละไฟล์แทนที่จะใช้express.static()เช่น:

<script src="/bootstrap.min.js"></script>

และรหัสเพื่อสร้างเส้นทางสำหรับสิ่งนั้น

app.get('/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});

หรือถ้าคุณยังต้องการแยกเส้นทางสำหรับสคริปต์ด้วย/scriptsคุณสามารถทำได้:

<script src="/scripts/bootstrap.min.js"></script>

และรหัสเพื่อสร้างเส้นทางสำหรับสิ่งนั้น

app.get('/scripts/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});

2
ฉันจำเป็นต้องคัดลอกสิ่งเหล่านั้นด้วยตนเองหรือมีวิธีที่น่ากลัวในการทำเช่นนั้นหรือไม่ ฉันคิดว่าวิธีที่ดีที่สุดคือการคัดลอกโฟลเดอร์ bootstrap อย่างสมบูรณ์/scriptsเพราะวิธีการอ้างอิงใด ๆ ภายในโมดูลจะได้รับการบำรุงรักษา
Chris

@phpheini - อาจช่วยได้: stackoverflow.com/questions/18966485/…และnpmjs.com/package/grunt-copy
jfriend00

1
@RobertOschler - ไม่ไม่ตรวจสอบดูเพล็กซ์ express.static()ส่งนัดแรกที่พบ เนื่องจากแต่ละexpress.static()คำสั่งจะสร้างเส้นทางการจับคู่ที่เป็นไปได้เพียงเส้นทางเดียวจึงไม่ควรซ้ำกันจากexpress.static()คำสั่งเดียว หากคุณมีหลายexpress.static()คำสั่งที่แต่ละคนสามารถจับคู่ได้คำแรกในรหัสของคุณคือคำที่จะใช้จับคู่ นอกจากนี้คุณไม่ควรมีหลายไฟล์ที่มีชื่อเดียวกันและพา ธ สัมพัทธ์ที่สามารถเข้าถึงได้โดยexpress.static()คำสั่ง แนวทางปฏิบัติที่ดีที่สุดคือไม่ควรทำเช่นนั้น
jfriend00

1
@RobertOschler - คุณต้องระวังให้มากเกี่ยวกับสิ่งที่คุณให้การเข้าถึงที่ไม่ได้ควบคุม โดยทั่วไปคุณควรชี้ไปexpress.static()ที่ไดเรกทอรีที่มีไฟล์สาธารณะเท่านั้น (รวมถึงไดเรกทอรีย่อย) ดังนั้นฉันไม่สามารถจินตนาการโครงการที่มีdistไดเรกทอรีจำนวนมากที่เผยแพร่ ดูเหมือนจะผิดปกติมากสำหรับฉัน บางทีคุณต้องการสร้างเส้นทางเฉพาะไปยังไฟล์เฉพาะหรือไฟล์ 2-3 ไฟล์ ในกรณีดังกล่าวคุณต้องรับผิดชอบในการแก้ปัญหาไฟล์เหล่านั้น มันจะไม่ทำให้คุณมีscript.jsไฟล์สี่ไฟล์เลย
jfriend00

1
@RobertOschler - หากคุณไม่ได้กำหนดเส้นทางที่ไม่ซ้ำกันไว้ข้างหน้าพวกเขาเพื่อที่จะจับคู่ไม่มีวิธีใดที่จะรู้ว่าโค้ดใดที่จะให้บริการเมื่อ/script.jsเบราว์เซอร์ร้องขอ ดังนั้นคำตอบที่เป็นนามธรรมคือคุณไม่ควรยอมให้สถานการณ์ของชื่อไฟล์ซ้ำกันเพราะมันไม่ใช่ปัญหาที่แก้ไขได้เว้นแต่คุณจะต้องการคำนำหน้าเฉพาะสำหรับแต่ละไดเรกทอรีของไฟล์ จากนั้นชื่อรูทที่ซ้ำกันจะไม่มีปัญหา สำหรับคำตอบที่เฉพาะเจาะจงยิ่งขึ้นพร้อมคำแนะนำโดยละเอียดคุณจะต้องโพสต์คำถามของคุณเองพร้อมรายละเอียดที่แน่นอน
jfriend00

18

ฉันจะใช้โมดูล path npm และทำสิ่งนี้:

var path = require('path');
app.use('/scripts', express.static(path.join(__dirname, 'node_modules/bootstrap/dist')));

สำคัญ:เราใช้ path.join เพื่อสร้างเส้นทางการเข้าร่วมโดยใช้วิธีไม่เชื่อเรื่องพระเจ้าเช่นใน windows และ unix เรามีตัวคั่นพา ธ ที่แตกต่างกัน (/ และ)


ทำเครื่องหมายว่าซ้ำกันข้างต้น path.join เป็นเพียงมาตรการเพิ่มเติม แต่ยังคงเป็นโซลูชันเดียวกันโดยการเพิ่มเส้นทางแบบคงที่ไปยัง node_modules dir
blamb

2
"path.join เป็นเพียงมาตรการเพิ่มเติม แต่ยังคงเป็นโซลูชันเดียวกัน" ไม่ใช่โซลูชันเดียวกัน การพูดอย่างเคร่งครัดจะใช้การเข้าร่วมเฉพาะระบบ (โปรดทราบ / และ \ ตัวคั่นใน windows และ unix)
Alexander Egorov

4
ตกลงฉันเห็นจุดของคุณใช่มันดีเสมอที่จะมีผู้ไม่เชื่อเรื่องพระเจ้าระบบฉันไม่ได้ตระหนักว่านั่นคือสิ่งที่ ขอบคุณสำหรับการชี้ให้เห็นว่า คุณควรเพิ่มคำนั้นลงในประโยคในคำตอบของคุณแทนที่จะให้รหัส :-) เช่นอธิบายรหัสของคุณ
blamb

10

ตามที่กล่าวไว้โดย jfriend00 คุณไม่ควรเปิดเผยโครงสร้างเซิร์ฟเวอร์ของคุณ public/scriptsคุณสามารถคัดลอกไฟล์พึ่งพาโครงการของคุณเพื่อสิ่งที่ต้องการ คุณสามารถทำได้อย่างง่ายดายด้วยdep-linkerเช่นนี้

var DepLinker = require('dep-linker');
DepLinker.copyDependenciesTo('./public/scripts')
// Done

1
สคริปต์srcจะเป็นอย่าง/scripts/[package-name]/dist/file.min.jsนั้น
จาค็อบฟอร์ด

7

หากคุณต้องการทางออกที่ง่ายและรวดเร็ว (และคุณติดตั้งอึก)

ในของgulpfile.jsฉันฉันเรียกใช้งานการคัดลอกวางง่ายที่ทำให้ไฟล์ใด ๆ ที่ฉันอาจต้องลงใน./public/modules/ไดเรกทอรี

gulp.task('modules', function() {
    sources = [
      './node_modules/prismjs/prism.js',
      './node_modules/prismjs/themes/prism-dark.css',
    ]
    gulp.src( sources ).pipe(gulp.dest('./public/modules/'));
});

gulp.task('copy-modules', ['modules']);

ข้อเสียของสิ่งนี้คือมันไม่อัตโนมัติ อย่างไรก็ตามหากคุณต้องการเพียงไม่กี่สคริปต์และรูปแบบการคัดลอก (และเก็บไว้ในรายการ) สิ่งนี้ควรทำงาน


หนึ่งสามารถเพิ่มใน package.json ของพวกเขาในสคริปต์'scripts': {'install':'yarn gulp copy-modules'}สมมติว่าเส้นด้ายเป็นผู้จัดการแพคเกจและอึกติดตั้งในแพคเกจ
ทอดด์

6

ไดเร็กทอรี 'node_modules' อาจไม่อยู่ในไดเรกทอรีปัจจุบันดังนั้นคุณควรแก้ไขพา ธ แบบไดนามิก

var bootstrap_dir = require.resolve('bootstrap')
                           .match(/.*\/node_modules\/[^/]+\//)[0];
app.use('/scripts', express.static(bootstrap_dir + 'dist/'));

+1 แต่ฉันไม่คิดว่ามันจะใช้ได้ในทุกกรณี - โมดูลเชื่อมโยง egan npm ที่ไม่ได้อยู่ในโฟลเดอร์ย่อย node_modules
Alasdair McLeay

3

ฉันต้องการอัปเดตคำถามนี้ด้วยวิธีแก้ปัญหาที่ง่ายกว่า สร้างลิงก์สัญลักษณ์ไปที่ node_modules

วิธีที่ง่ายที่สุดในการให้สิทธิการเข้าถึงแก่ node_modules คือการสร้างลิงก์สัญลักษณ์ที่ชี้ไปยัง node_modules ของคุณจากภายในไดเร็กทอรีพับลิกของคุณ symlink จะทำให้มันราวกับว่าไฟล์ที่มีอยู่ทุกที่ที่ลิงค์ถูกสร้างขึ้น

ตัวอย่างเช่นหากเซิร์ฟเวอร์โหนดมีรหัสสำหรับการให้บริการไฟล์คงที่

app.use(serveStatic(path.join(__dirname, 'dist')));

และ __dirname อ้างถึง / path / to / app เพื่อให้ไฟล์สแตติกของคุณถูกแสดงจาก / path / to / app / dist

และ node_modules อยู่ที่ / path / to / app / node_modules จากนั้นสร้าง symlink แบบนี้บน mac / linux:

ln -s /path/to/app/node_modules /path/to/app/dist/node_modules

หรือเช่นนี้ใน windows:

mklink /path/to/app/node_modules /path/to/app/dist/node_modules

ตอนนี้รับคำขอสำหรับ:

node_modules/some/path 

จะได้รับการตอบกลับด้วยไฟล์ที่

/path/to/app/dist/node_modules/some/path 

ซึ่งเป็นไฟล์จริงๆที่

/path/to/app/node_modules/some/path

หากไดเรกทอรีของคุณที่ / path / to / app / dist ไม่ใช่ตำแหน่งที่ปลอดภัยอาจเป็นเพราะการรบกวนจากกระบวนการสร้างด้วย gulp หรือ grunt คุณสามารถเพิ่มไดเรกทอรีแยกต่างหากสำหรับลิงก์และเพิ่มบริการ servStatic ใหม่เช่น:

ln -s /path/to/app/node_modules /path/to/app/newDirectoryName/node_modules

และในโหนดเพิ่ม:

app.use(serveStatic(path.join(__dirname, 'newDirectoryName')));

1
แต่คุณย้ายแอปของคุณไปยังเส้นทางอื่นแล้ว symlink ไม่ถูกต้อง หรือคุณต้องการเรียกใช้แอปของคุณบนเครื่องอื่น (ทดสอบ / ผลิตภัณฑ์) คุณจะต้องสร้างมันขึ้นมา ผู้มีส่วนร่วมในแอปของคุณจะต้องทำเช่นเดียวกัน มันเพิ่มการบำรุงรักษาบางอย่างมากกว่าการแก้ปัญหาข้างต้น
mati.o

@ mati.o แล้วลิงก์สัมพัทธ์สัมพัทธ์ล่ะ? ฉันชอบโซลูชันนี้ แต่มี symlink แบบสัมพัทธ์เท่านั้น
LukášBednařík

3

ฉันไม่พบวิธีแก้ปัญหาใด ๆ ที่สะอาด (ฉันไม่ต้องการเปิดเผยที่มาของ node_modules ทั้งหมดของฉัน) ดังนั้นฉันเพิ่งเขียนสคริปต์ Powershell เพื่อคัดลอก:

$deps = "leaflet", "leaflet-search", "material-components-web"

foreach ($dep in $deps) {
    Copy-Item "node_modules/$dep/dist" "static/$dep" -Recurse
}

1

ฉันได้ทำการเปลี่ยนแปลงด้านล่างเป็น AUTO-INCLUDE ไฟล์ในดัชนี html ดังนั้นเมื่อคุณเพิ่มไฟล์ในโฟลเดอร์มันจะถูกเลือกโดยอัตโนมัติจากโฟลเดอร์โดยไม่ต้องรวมไฟล์ไว้ใน index.html

//// THIS WORKS FOR ME 
///// in app.js or server.js

var app = express();

app.use("/", express.static(__dirname));
var fs = require("fs"),

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}
//// send the files in js folder as variable/array 
ejs = require('ejs');

res.render('index', {
    'something':'something'...........
    jsfiles: jsfiles,
});

///--------------------------------------------------

///////// in views/index.ejs --- the below code will list the files in index.ejs

<% for(var i=0; i < jsfiles.length; i++) { %>
   <script src="<%= jsfiles[i] %>"></script>
<% } %>

1

นี่คือสิ่งที่ฉันได้ติดตั้งบนexpressเซิร์ฟเวอร์ของฉัน:

// app.js
const path = require('path');
const express = require('express');
const expressApp  = express();
const nm_dependencies = ['bootstrap', 'jquery', 'popper.js']; // keep adding required node_modules to this array.
nm_dependencies.forEach(dep => {
  expressApp.use(`/${dep}`, express.static(path.resolve(`node_modules/${dep}`)));
});

<!-- somewhere inside head tag -->
<link rel="stylesheet" href="bootstrap/dist/css/bootstrap.css" />

<!-- somewhere near ending body tag -->
<script src="jquery/dist/jquery.js" charset="utf-8"></script>
<script src="popper.js/dist/popper.js" charset="utf-8"></script>
<script src="bootstrap/dist/js/bootstrap.js" charset="utf-8"></script>

โชคดี...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.